summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <syn@sceen.net>2006-05-30 12:16:40 +0000
committerRichard Braun <syn@sceen.net>2006-05-30 12:16:40 +0000
commit3d937ef6781e30ad95239cc2c7d78e44589d26d8 (patch)
tree2b93e59b468da6de9ef8fd57ee2d93bc1e9e5164
parentb77fec789b66c2611d2a9b1cdcb607d0865e32c2 (diff)
Esthetic change.
-rw-r--r--mtxexpression.cc211
-rw-r--r--mtxexpression.h63
2 files changed, 264 insertions, 10 deletions
diff --git a/mtxexpression.cc b/mtxexpression.cc
index a6bc695..f18e7be 100644
--- a/mtxexpression.cc
+++ b/mtxexpression.cc
@@ -35,6 +35,18 @@ using namespace std;
/*
* See mtxexpression.h.
*/
+struct mtx_function MtxExpression::functions[] =
+{
+ {"det", MTXEXPRESSION_FUNCTION_DETERMINANT, 1},
+ {"inverse", MTXEXPRESSION_FUNCTION_INVERSE, 1},
+ {"transpose", MTXEXPRESSION_FUNCTION_TRANSPOSE, 1},
+ {"augment", MTXEXPRESSION_FUNCTION_AUGMENT, 2},
+ {NULL, MTXEXPRESSION_FUNCTION_NULL}
+};
+
+/*
+ * See mtxexpression.h.
+ */
struct mtx_operator MtxExpression::operators[][6] =
{
{
@@ -107,8 +119,11 @@ MtxExpression::MtxExpression(MtxLanguage *language,
MtxInteger(element.c_str())));
}
+ else if (isVariableName(element))
+ expressions.push_back(new MtxSymbol(language, element));
+
else
- expressions.push_back(new MtxSymbol(language, *lexical_elements.begin()));
+ throw MtxException("invalid variable name");
function = MTXEXPRESSION_FUNCTION_NULL;
}
@@ -218,7 +233,8 @@ MtxExpression::MtxExpression(MtxLanguage *language,
expressions.push_back(new MtxExpression(language, second_operand));
}
- else if (lexical_elements.size() > 1 && lexical_elements.back() == ")")
+ else if (lexical_elements.size() > 2 && lexical_elements[0] == "("
+ && lexical_elements.back() == ")")
{
lexical_elements.erase(lexical_elements.begin());
lexical_elements.erase(lexical_elements.end() - 1);
@@ -252,8 +268,13 @@ MtxExpression::MtxExpression(MtxLanguage *language,
integer = dynamic_cast<MtxInteger *>(value);
if (integer == NULL)
- throw MtxException("matrix cell not integer or "
- "rational");
+ {
+ delete symbols[i];
+ delete value;
+ delete[] rationals;
+ throw MtxException("matrix cell not integer or "
+ "rational");
+ }
else
rationals[i] = *integer;
@@ -273,6 +294,38 @@ MtxExpression::MtxExpression(MtxLanguage *language,
function = MTXEXPRESSION_FUNCTION_NULL;
}
+ else if (lexical_elements.size() > 3 && lexical_elements[1] == "("
+ && lexical_elements.back() == ")")
+ {
+ vector<MtxSymbol *> symbols;
+ size_t i;
+
+ i = 0;
+
+ while (functions[i].str != NULL)
+ {
+ if (lexical_elements[0] == functions[i].str)
+ break;
+
+ i++;
+ }
+
+ if (functions[i].str == NULL)
+ throw MtxException("call to unknown function");
+
+ function = functions[i].id;
+ lexical_elements.erase(lexical_elements.begin());
+ lexical_elements.erase(lexical_elements.begin());
+ lexical_elements.erase(lexical_elements.end() - 1);
+ parseArguments(lexical_elements, symbols);
+
+ if (symbols.size() != functions[i].argc)
+ throw MtxException("wrong number of arguments in function call");
+
+ for (i = 0; i < symbols.size(); i++)
+ expressions.push_back(symbols[i]);
+ }
+
else
throw MtxException("syntax error");
}
@@ -290,12 +343,12 @@ MtxExpression::~MtxExpression()
#define MATRIX_DIMENSIONS_ERROR(symbols) \
{ \
- freeMatrix(symbols); \
+ freeSymbols(symbols); \
throw MtxException("number of columns mismatch at matrix creation"); \
}
void
-MtxExpression::freeMatrix(vector<MtxSymbol *> &symbols) const
+MtxExpression::freeSymbols(vector<MtxSymbol *> &symbols) const
{
vector<MtxSymbol *>::iterator iterator;
@@ -397,6 +450,63 @@ MtxExpression::parseMatrix(const mtx_expression_t &lexical_elements,
MATRIX_DIMENSIONS_ERROR(symbols);
}
+void
+MtxExpression::parseArguments(const mtx_expression_t &lexical_elements,
+ vector<MtxSymbol *> &symbols) const
+{
+ mtx_expression_t::const_iterator iterator;
+ size_t p_level, b_level;
+ mtx_expression_t tmp;
+
+ if (lexical_elements.empty())
+ throw MtxException("syntax error");
+
+ p_level = 0;
+ b_level = 0;
+
+ for (iterator = lexical_elements.begin();
+ iterator != lexical_elements.end();
+ iterator++)
+ {
+ if (p_level == 0 && b_level == 0 && *iterator == ",")
+ {
+ if (tmp.empty())
+ {
+ freeSymbols(symbols);
+ throw MtxException("syntax error");
+ }
+
+ symbols.push_back(new MtxExpression(language, tmp));
+ tmp.clear();
+ }
+
+ else
+ {
+ if (*iterator == "(")
+ p_level++;
+
+ else if (*iterator == ")")
+ p_level--;
+
+ else if (*iterator == "[")
+ b_level++;
+
+ else if (*iterator == "]")
+ b_level--;
+
+ tmp.push_back(*iterator);
+ }
+ }
+
+ if (tmp.empty())
+ {
+ freeSymbols(symbols);
+ throw MtxException("syntax error");
+ }
+
+ symbols.push_back(new MtxExpression(language, tmp));
+}
+
bool
MtxExpression::isOperator(const string &str)
{
@@ -422,6 +532,24 @@ MtxExpression::isOperator(const string &str)
return false;
}
+bool
+MtxExpression::isVariableName(const string &str)
+{
+ size_t i;
+
+ if (str.length() == 0)
+ return false;
+
+ if (isdigit(str[0]))
+ return false;
+
+ for (i = 0; i < str.length(); i++)
+ if (!(isalnum(str[i]) || str[i] == '_'))
+ return false;
+
+ return true;
+}
+
mtx_expression_t::iterator
MtxExpression::findOperator(mtx_expression_t &lexical_elements, const char *str)
{
@@ -502,9 +630,13 @@ MtxExpression::getSymbol(bool create, bool fail_if_special) const
else
{
+ MtxMatrix *matrix, *matrix2;
MtxSymbol symbol;
MtxValue *value;
+ /*
+ * XXX I usually never do this, and was a little short on time.
+ */
switch (function)
{
case MTXEXPRESSION_FUNCTION_NULL:
@@ -596,6 +728,73 @@ MtxExpression::getSymbol(bool create, bool fail_if_special) const
symbol.setName(expressions[0]->getSymbol(true).getName());
language->setSymbol(symbol);
return symbol;
+
+ case MTXEXPRESSION_FUNCTION_DETERMINANT:
+ value = expressions[0]->getSymbol().getValue()->clone();
+ matrix = dynamic_cast<MtxMatrix *>(value);
+
+ if (matrix == NULL)
+ {
+ delete value;
+ throw MtxException("argument is not a matrix");
+ }
+
+ symbol = MtxSymbol(language, matrix->determinant());
+ delete matrix;
+ return symbol;
+
+ case MTXEXPRESSION_FUNCTION_INVERSE:
+ value = expressions[0]->getSymbol().getValue()->clone();
+ matrix = dynamic_cast<MtxMatrix *>(value);
+
+ if (matrix == NULL)
+ {
+ delete value;
+ throw MtxException("argument is not a matrix");
+ }
+
+ symbol = MtxSymbol(language, matrix->inverted());
+ delete matrix;
+ return symbol;
+
+ case MTXEXPRESSION_FUNCTION_TRANSPOSE:
+ value = expressions[0]->getSymbol().getValue()->clone();
+ matrix = dynamic_cast<MtxMatrix *>(value);
+
+ if (matrix == NULL)
+ {
+ delete value;
+ throw MtxException("argument is not a matrix");
+ }
+
+ symbol = MtxSymbol(language, matrix->transpose());
+ delete matrix;
+ return symbol;
+
+ case MTXEXPRESSION_FUNCTION_AUGMENT:
+ value = expressions[0]->getSymbol().getValue()->clone();
+ matrix = dynamic_cast<MtxMatrix *>(value);
+
+ if (matrix == NULL)
+ {
+ delete value;
+ throw MtxException("argument is not a matrix");
+ }
+
+ value = expressions[1]->getSymbol().getValue()->clone();
+ matrix2 = dynamic_cast<MtxMatrix *>(value);
+
+ if (matrix2 == NULL)
+ {
+ delete matrix;
+ delete value;
+ throw MtxException("argument is not a matrix");
+ }
+
+ symbol = MtxSymbol(language, matrix->augmented(*matrix2));
+ delete matrix;
+ delete matrix2;
+ return symbol;
}
throw MtxException("operator/function not yet implemented");
diff --git a/mtxexpression.h b/mtxexpression.h
index 16051b6..e22dcfe 100644
--- a/mtxexpression.h
+++ b/mtxexpression.h
@@ -34,7 +34,7 @@
/**
* \enum mtx_function_id
- * \brief ID of a function/operator (e.g. assignment, addition).
+ * \brief ID of a function/operator. E.g. assignment, addition.
*/
enum mtx_function_id
{
@@ -47,7 +47,11 @@ enum mtx_function_id
MTXEXPRESSION_FUNCTION_MULTIPLY,
MTXEXPRESSION_FUNCTION_MULTIPLY_ASSIGN,
MTXEXPRESSION_FUNCTION_DIVIDE,
- MTXEXPRESSION_FUNCTION_DIVIDE_ASSIGN
+ MTXEXPRESSION_FUNCTION_DIVIDE_ASSIGN,
+ MTXEXPRESSION_FUNCTION_DETERMINANT,
+ MTXEXPRESSION_FUNCTION_INVERSE,
+ MTXEXPRESSION_FUNCTION_TRANSPOSE,
+ MTXEXPRESSION_FUNCTION_AUGMENT
};
/**
@@ -62,7 +66,30 @@ enum mtx_operator_associativity
};
/**
+ * A function.
+ */
+struct mtx_function
+{
+ /**
+ * Function string as entered by the user.
+ */
+ char *str;
+
+ /**
+ * ID of the function.
+ */
+ enum mtx_function_id id;
+
+ /**
+ * Number of arguments.
+ */
+ size_t argc;
+};
+
+/**
* An operator.
+ *
+ * XXX Inheritence from struct mtx_function seems to cause trouble. Why ?
*/
struct mtx_operator
{
@@ -141,9 +168,10 @@ class MtxExpression: public MtxSymbol
/**
* Free the pointers stored in the given vector of symbols.
*
- * Mainly used after parsing a matrix is done or failed.
+ * Mainly used after parsing a matrix or function arguments is done or
+ * failed.
*/
- void freeMatrix(std::vector<MtxSymbol *> &symbols) const;
+ void freeSymbols(std::vector<MtxSymbol *> &symbols) const;
/**
* Parse the given lexical elements and extract symbols and expressions
@@ -160,6 +188,21 @@ class MtxExpression: public MtxSymbol
std::vector<MtxSymbol *> &symbols,
size_t &rows, size_t &columns) const;
+ /**
+ * Parse the given lexical elements and extract symbols and expressions
+ * from it to create the list of arguments of a function. An exception is
+ * thrown if the syntax is invalid.
+ *
+ * @param lexical_elements vector of strings to parse
+ * @param symbols vector of symbols/expressions updated by this method
+ */
+ void parseArguments(const mtx_expression_t &lexical_elements,
+ std::vector<MtxSymbol *> &symbols) const;
+
+ /**
+ * Array of builtin functions.
+ */
+ static struct mtx_function functions[];
/**
* Multidimensional array of supported operators.
@@ -171,14 +214,26 @@ class MtxExpression: public MtxSymbol
*
* XXX There are at most 5 operators for the same precedence (+ a null
* entry to indicate end of list), so the second dimension is 6.
+ *
+ * @see isOperator()
*/
static struct mtx_operator operators[][6];
/**
* Return true if the given string matches an operator.
+ *
+ * @see operators()
*/
static bool isOperator(const std::string &str);
+ /**
+ * Return true if the given string is a valid variable name.
+ *
+ * A valid variable name consist of [a-zA-Z0-9_] characters only,
+ * and cannot begin with a digit.
+ */
+ static bool isVariableName(const std::string &str);
+
public:
/**
* Create an expression from a set of lexical elements.