/** * Visits the given ASTNode as a unary minus. For this node only the * traversal is preorder. */ void L3FormulaFormatter_visitUMinus ( const ASTNode_t *parent, const ASTNode_t *node, StringBuffer_t *sb, const L3ParserSettings_t *settings ) { //Unary minus is *not* the highest precedence, since it is superceded by 'power' unsigned int group; //If we are supposed to collapse minuses, do so. if (L3ParserSettings_getParseCollapseMinus(settings)) { if (ASTNode_getNumChildren(node) == 1 && ASTNode_isUMinus(ASTNode_getLeftChild(node))) { L3FormulaFormatter_visit(parent, ASTNode_getLeftChild(ASTNode_getLeftChild(node)), sb, settings); return; } } group = L3FormulaFormatter_isGrouped(parent, node, settings); if (group) { StringBuffer_appendChar(sb, '('); } StringBuffer_appendChar(sb, '-'); L3FormulaFormatter_visit ( node, ASTNode_getLeftChild(node), sb, settings); if (group) { StringBuffer_appendChar(sb, ')'); } }
/** * Visits the given ASTNode, translating the piecewise function * to the much simpler 'x % y' format. */ void L3FormulaFormatter_visitModulo ( const ASTNode_t *parent, const ASTNode_t *node, StringBuffer_t *sb, const L3ParserSettings_t *settings ) { unsigned int group = L3FormulaFormatter_isGrouped(parent, node, settings); const ASTNode_t* subnode = ASTNode_getLeftChild(node); if (group) { StringBuffer_appendChar(sb, '('); } //Get x and y from the first child of the piecewise function, // then the first child of that (times), and the first child // of that (minus). L3FormulaFormatter_visit ( subnode, ASTNode_getLeftChild(subnode), sb, settings); StringBuffer_appendChar(sb, ' '); StringBuffer_appendChar(sb, '%'); StringBuffer_appendChar(sb, ' '); subnode = ASTNode_getRightChild(subnode); L3FormulaFormatter_visit ( node, ASTNode_getLeftChild(subnode), sb, settings); if (group) { StringBuffer_appendChar(sb, ')'); } }
/** * @return true (non-zero) if the given child ASTNode should be grouped * (with parenthesis), false (0) otherwise. * * A node should be group if it is not an argument to a function and * either: * * - The parent node has higher precedence than the child, or * * - If parent node has equal precedence with the child and the child is * to the right. In this case, operator associativity and right-most * AST derivation enforce the grouping. */ int L3FormulaFormatter_isGrouped (const ASTNode_t *parent, const ASTNode_t *child, const L3ParserSettings_t *settings) { int pp, cp; int pt, ct; int group = 0; int parentmodulo = 0; if (parent != NULL) { parentmodulo = isTranslatedModulo(parent); if (parentmodulo || !L3FormulaFormatter_isFunction(parent, settings)) { group = 1; pp = getL3Precedence(parent); cp = getL3Precedence(child); if (pp < cp) { group = 0; } else if (pp == cp) { if (parentmodulo) { //Always group: x * y % z -> (x * y) % z group = 1; } /** * Don't group only if i) child is the first on the list and ii) both parent and * child are the same type, or if they * should be associative operators (i.e. not AST_MINUS or * AST_DIVIDE). That is, do not group a parent and left child * that are either both AST_PLUS or both AST_TIMES operators, nor the logical operators * that have the same precedence. */ if (ASTNode_getLeftChild(parent) == child) { pt = ASTNode_getType(parent); ct = ASTNode_getType(child); if (ASTNode_isLogical(parent) || ASTNode_isRelational(parent)) { group = !(pt == ct); } else { group = !((pt == ct) || (pt == AST_PLUS || pt == AST_TIMES)); } } } else if (pp==7 && cp==6) { //If the parent is 'power' and the child is 'unary not' or 'unary minus', we only need // to group if the child is the *left* child: '(-x)^y', but 'x^-y'. if (!(ASTNode_getLeftChild(parent) == child)) { group = 0; } } } } return group; }
/** * Visits the given ASTNode as a unary minus. For this node only the * traversal is preorder. * Writes the function as a directed graph and appends the result * to the StringBuffer. */ void FormulaGraphvizFormatter_visitUMinus (const ASTNode_t *parent, const ASTNode_t *node, StringBuffer_t *sb ) { char *uniqueName = FormulaGraphvizFormatter_getUniqueName(node); char *name = FormulaGraphvizFormatter_format(node); StringBuffer_append(sb, uniqueName); StringBuffer_append(sb, " [shape=box, label="); StringBuffer_append(sb, name); StringBuffer_append(sb, "];\n"); if (parent != NULL) { uniqueName = FormulaGraphvizFormatter_getUniqueName(parent); name = FormulaGraphvizFormatter_getUniqueName(node); if(strcmp(name, uniqueName)) { StringBuffer_append(sb, uniqueName); StringBuffer_append(sb, " -> "); StringBuffer_append(sb, name); StringBuffer_append(sb, ";\n"); } } FormulaGraphvizFormatter_visit ( node, ASTNode_getLeftChild(node), sb ); }
END_TEST START_TEST (test_SBML_parseFormula_15) { ASTNode_t *r = SBML_parseFormula("foo(1, bar)"); ASTNode_t *c; fail_unless( ASTNode_getType(r) == AST_FUNCTION , NULL ); fail_unless( !strcmp(ASTNode_getName(r), "foo") , NULL ); fail_unless( ASTNode_getNumChildren(r) == 2 , NULL ); c = ASTNode_getLeftChild(r); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 1, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild(r); fail_unless( ASTNode_getType(c) == AST_NAME , NULL ); fail_unless( !strcmp(ASTNode_getName(c), "bar") , NULL ); fail_unless( ASTNode_getNumChildren(c) == 0 , NULL ); ASTNode_free(r); }
END_TEST START_TEST (test_SBML_parseFormula_6) { ASTNode_t *r = SBML_parseFormula("1 + 2"); ASTNode_t *c; fail_unless( ASTNode_getType (r) == AST_PLUS, NULL ); fail_unless( ASTNode_getCharacter (r) == '+', NULL ); fail_unless( ASTNode_getNumChildren(r) == 2 , NULL ); c = ASTNode_getLeftChild(r); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 1, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild(r); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 2, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); ASTNode_free(r); }
/** * Visits the given ASTNode as a unary minus. For this node only the * traversal is preorder. */ void FormulaFormatter_visitUMinus ( const ASTNode_t *parent, const ASTNode_t *node, StringBuffer_t *sb ) { StringBuffer_appendChar(sb, '-'); FormulaFormatter_visit ( node, ASTNode_getLeftChild(node), sb ); }
END_TEST START_TEST (test_SBML_parseFormula_11) { ASTNode_t *r = SBML_parseFormula("1 - -foo / 3"); ASTNode_t *c; fail_unless( ASTNode_getType (r) == AST_MINUS, NULL ); fail_unless( ASTNode_getCharacter (r) == '-', NULL ); fail_unless( ASTNode_getNumChildren(r) == 2 , NULL ); c = ASTNode_getLeftChild(r); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 1, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild(r); fail_unless( ASTNode_getType (c) == AST_DIVIDE, NULL ); fail_unless( ASTNode_getCharacter (c) == '/', NULL ); fail_unless( ASTNode_getNumChildren(c) == 2, NULL ); c = ASTNode_getLeftChild( ASTNode_getRightChild(r) ); fail_unless( ASTNode_getType (c) == AST_MINUS, NULL ); fail_unless( ASTNode_getCharacter (c) == '-', NULL ); fail_unless( ASTNode_getNumChildren(c) == 1 , NULL ); c = ASTNode_getLeftChild( ASTNode_getLeftChild( ASTNode_getRightChild(r) ) ); fail_unless( ASTNode_getType(c) == AST_NAME , NULL ); fail_unless( !strcmp(ASTNode_getName(c), "foo") , NULL ); fail_unless( ASTNode_getNumChildren(c) == 0 , NULL ); c = ASTNode_getRightChild( ASTNode_getRightChild(r) ); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 3, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); ASTNode_free(r); }
END_TEST START_TEST (test_SBML_parseFormula_10) { ASTNode_t *r = SBML_parseFormula("1 + -2e100 / 3"); ASTNode_t *c; fail_unless( ASTNode_getType (r) == AST_PLUS, NULL ); fail_unless( ASTNode_getCharacter (r) == '+', NULL ); fail_unless( ASTNode_getNumChildren(r) == 2 , NULL ); c = ASTNode_getLeftChild(r); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 1, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild(r); fail_unless( ASTNode_getType (c) == AST_DIVIDE, NULL ); fail_unless( ASTNode_getCharacter (c) == '/', NULL ); fail_unless( ASTNode_getNumChildren(c) == 2 , NULL ); c = ASTNode_getLeftChild(c); fail_unless( ASTNode_getType (c) == AST_REAL_E, NULL ); fail_unless( ASTNode_getMantissa (c) == -2, NULL ); fail_unless( ASTNode_getExponent (c) == 100, NULL ); fail_unless( ASTNode_getReal (c) == -2e+100, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild( ASTNode_getRightChild(r) ); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 3, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); ASTNode_free(r); }
END_TEST START_TEST (test_SBML_parseFormula_8) { ASTNode_t *r = SBML_parseFormula("(1 - 2) * 3"); ASTNode_t *c; fail_unless( ASTNode_getType (r) == AST_TIMES, NULL ); fail_unless( ASTNode_getCharacter (r) == '*', NULL ); fail_unless( ASTNode_getNumChildren(r) == 2 , NULL ); c = ASTNode_getLeftChild(r); fail_unless( ASTNode_getType (c) == AST_MINUS, NULL ); fail_unless( ASTNode_getCharacter (c) == '-', NULL ); fail_unless( ASTNode_getNumChildren(c) == 2, NULL ); c = ASTNode_getRightChild(r); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 3, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getLeftChild( ASTNode_getLeftChild(r) ); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 1, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild( ASTNode_getLeftChild(r) ); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 2, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); ASTNode_free(r); }
END_TEST START_TEST (test_SBML_parseFormula_12) { ASTNode_t *r = SBML_parseFormula("2 * foo^bar + 3.0"); ASTNode_t *c; fail_unless( ASTNode_getType (r) == AST_PLUS, NULL ); fail_unless( ASTNode_getCharacter (r) == '+', NULL ); fail_unless( ASTNode_getNumChildren(r) == 2 , NULL ); c = ASTNode_getLeftChild(r); fail_unless( ASTNode_getType (c) == AST_TIMES, NULL ); fail_unless( ASTNode_getCharacter (c) == '*', NULL ); fail_unless( ASTNode_getNumChildren(c) == 2 , NULL ); c = ASTNode_getRightChild(r); fail_unless( ASTNode_getType (c) == AST_REAL, NULL ); fail_unless( ASTNode_getReal (c) == 3.0, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0 , NULL ); c = ASTNode_getLeftChild( ASTNode_getLeftChild(r) ); fail_unless( ASTNode_getType (c) == AST_INTEGER, NULL ); fail_unless( ASTNode_getInteger (c) == 2, NULL ); fail_unless( ASTNode_getNumChildren(c) == 0, NULL ); c = ASTNode_getRightChild( ASTNode_getLeftChild(r) ); fail_unless( ASTNode_getType (c) == AST_POWER, NULL ); fail_unless( ASTNode_getCharacter (c) == '^', NULL ); fail_unless( ASTNode_getNumChildren(c) == 2 , NULL ); c = ASTNode_getLeftChild( ASTNode_getRightChild( ASTNode_getLeftChild(r) ) ); fail_unless( ASTNode_getType(c) == AST_NAME , NULL ); fail_unless( !strcmp(ASTNode_getName(c), "foo") , NULL ); fail_unless( ASTNode_getNumChildren(c) == 0 , NULL ); c = ASTNode_getRightChild( ASTNode_getRightChild( ASTNode_getLeftChild(r) ) ); fail_unless( ASTNode_getType(c) == AST_NAME , NULL ); fail_unless( !strcmp(ASTNode_getName(c), "bar") , NULL ); fail_unless( ASTNode_getNumChildren(c) == 0 , NULL ); ASTNode_free(r); }
/** * Visits the given ASTNode as a unary not. */ void L3FormulaFormatter_visitUNot ( const ASTNode_t *parent, const ASTNode_t *node, StringBuffer_t *sb, const L3ParserSettings_t *settings ) { //Unary not is also not the highest precedence, since it is superceded by 'power' unsigned int group = L3FormulaFormatter_isGrouped(parent, node, settings); if (group) { StringBuffer_appendChar(sb, '('); } StringBuffer_appendChar(sb, '!'); L3FormulaFormatter_visit ( node, ASTNode_getLeftChild(node), sb, settings); if (group) { StringBuffer_appendChar(sb, ')'); } }
/** * Visits the given ASTNode and continues the inorder traversal. * Writes the function as a directed graph and appends the result * to the StringBuffer. */ void FormulaGraphvizFormatter_visitOther (const ASTNode_t *parent, const ASTNode_t *node, StringBuffer_t *sb ) { unsigned int numChildren = ASTNode_getNumChildren(node); char *name; char *uniqueName; if (numChildren > 0) { uniqueName = FormulaGraphvizFormatter_getUniqueName(node); name = FormulaGraphvizFormatter_format(node); StringBuffer_append(sb, uniqueName); StringBuffer_append(sb, " [shape=box, label="); StringBuffer_append(sb, name); StringBuffer_append(sb, "];\n"); FormulaGraphvizFormatter_visit( node, ASTNode_getLeftChild(node), sb ); } if (parent != NULL) { name = FormulaGraphvizFormatter_getUniqueName(node); uniqueName = FormulaGraphvizFormatter_getUniqueName(parent); if(strcmp(name, uniqueName)) { StringBuffer_append(sb, uniqueName); StringBuffer_append(sb, " -> "); StringBuffer_append(sb, name); StringBuffer_append(sb, ";\n"); } } if (numChildren > 1) { FormulaGraphvizFormatter_visit( node, ASTNode_getRightChild(node), sb ); } }
void printFunctionDefinition (unsigned int n, const FunctionDefinition_t *fd) { const ASTNode_t *math; char *formula; if ( FunctionDefinition_isSetMath(fd) ) { printf("FunctionDefinition %d, %s(", n, FunctionDefinition_getId(fd)); math = FunctionDefinition_getMath(fd); /* Print function arguments. */ if (ASTNode_getNumChildren(math) > 1) { printf("%s", ASTNode_getName( ASTNode_getLeftChild(math) )); for (n = 1; n < ASTNode_getNumChildren(math) - 1; ++n) { printf(", %s", ASTNode_getName( ASTNode_getChild(math, n) )); } } printf(") := "); /* Print function body. */ if (ASTNode_getNumChildren(math) == 0) { printf("(no body defined)"); } else { math = ASTNode_getChild(math, ASTNode_getNumChildren(math) - 1); formula = SBML_formulaToString(math); printf("%s\n", formula); free(formula); } } }
void alg_alter_tree_structure(ASTNode_t **node_p, ASTNode_t *parent, int child_order) { ASTNode_t *node, *left, *right; ASTNode_t *times_node, *one_node; node = *node_p; if((left=ASTNode_getLeftChild(node)) != NULL) { alg_alter_tree_structure(&left, node, 0); } if((right=ASTNode_getRightChild(node)) != NULL) { alg_alter_tree_structure(&right, node, 1); } if(ASTNode_getType(node) == AST_NAME) { times_node = ASTNode_createWithType(AST_TIMES); one_node = ASTNode_createWithType(AST_INTEGER); ASTNode_setInteger(one_node, 1); ASTNode_addChild(times_node, one_node); ASTNode_addChild(times_node, node); if(parent != NULL) { ASTNode_replaceChild(parent, child_order, times_node); } else { *node_p = times_node; } } return; }
END_TEST START_TEST (test_FormulaFormatter_isGrouped) { ASTNode_t *p = ASTNode_create(); ASTNode_t *c; /** Empty parent, p is the root of the tree. **/ fail_unless( FormulaFormatter_isGrouped(NULL, p) == 0, NULL ); ASTNode_free(p); /** "1 + 2 * 3" **/ p = SBML_parseFormula("1 + 2 * 3"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); /** "(1 + 2) * 3" **/ p = SBML_parseFormula("(1 + 2) * 3"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 1, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); /** * "1 + (2 * 3)": * * In this case, explicit grouping is not needed due to operator * precedence rules. */ p = SBML_parseFormula("1 + (2 * 3)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); /** * "foo(1 + 2, 2 * 3)": * * The parent node foo has higher precedence than its children, but * grouping is not nescessary since foo is a function. */ p = SBML_parseFormula("foo(1 + 2, 2 * 3)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); /** * "(a / b) * c": * * In this case, explicit grouping is not needed due to associativity * rules. */ p = SBML_parseFormula("(a / b) * c"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); /** * "a / (b * c)": * * In this case, explicit grouping is needed. The operators / and * have * the same precedence, but the parenthesis modifies the associativity. */ p = SBML_parseFormula("a / (b * c)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 1, NULL ); ASTNode_free(p); /** * "a - (b - c)": * * Rainer Machne reported that the above parsed correctly, but was not * formatted correctly. * * The bug was in FormulaFormatter_isGrouped(). While it was correctly * handling parent and child ASTNodes of the same precedence, it was not * handling the special subcase where parent and child nodes were the * same operator. For grouping, this only matters for the subtraction * and division operators, as they are not associative. * * An exhaustive set of eight tests follow. */ p = SBML_parseFormula("a - (b - c)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 1, NULL ); ASTNode_free(p); p = SBML_parseFormula("a - b - c"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); p = SBML_parseFormula("a + (b + c)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); p = SBML_parseFormula("a + b + c"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); p = SBML_parseFormula("a * (b * c)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); p = SBML_parseFormula("a * b * c"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); p = SBML_parseFormula("a / (b / c)"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 1, NULL ); ASTNode_free(p); p = SBML_parseFormula("a / b / c"); c = ASTNode_getLeftChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); c = ASTNode_getRightChild(p); fail_unless( FormulaFormatter_isGrouped(p, c) == 0, NULL ); ASTNode_free(p); }