From 6232079f021be878feabd22e59ab0b7e10ba9d73 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 31 Mar 2016 18:47:18 +0200 Subject: [PATCH] Poincare: Add a Simplification rule generator Change-Id: I4a0971405164c40c5ca3f7e1a0406f01d83d67d8 --- poincare/src/simplify/expression_selector.cpp | 15 +- poincare/src/simplify/expression_selector.h | 6 +- .../src/simplify/rules_generation/Makefile | 16 +++ .../src/simplify/rules_generation/builder.cpp | 30 ++++ .../src/simplify/rules_generation/builder.h | 22 +++ .../src/simplify/rules_generation/node.cpp | 67 +++++++++ poincare/src/simplify/rules_generation/node.h | 23 ++++ .../src/simplify/rules_generation/rule.cpp | 25 ++++ poincare/src/simplify/rules_generation/rule.h | 18 +++ .../simplify/rules_generation/rules_lexer.l | 22 +++ .../simplify/rules_generation/rules_parser.y | 130 ++++++++++++++++++ .../simplify/rules_generation/selector.cpp | 24 ++++ .../src/simplify/rules_generation/selector.h | 21 +++ poincare/src/simplify/simplification.cpp | 2 +- 14 files changed, 415 insertions(+), 6 deletions(-) create mode 100644 poincare/src/simplify/rules_generation/Makefile create mode 100644 poincare/src/simplify/rules_generation/builder.cpp create mode 100644 poincare/src/simplify/rules_generation/builder.h create mode 100644 poincare/src/simplify/rules_generation/node.cpp create mode 100644 poincare/src/simplify/rules_generation/node.h create mode 100644 poincare/src/simplify/rules_generation/rule.cpp create mode 100644 poincare/src/simplify/rules_generation/rule.h create mode 100644 poincare/src/simplify/rules_generation/rules_lexer.l create mode 100644 poincare/src/simplify/rules_generation/rules_parser.y create mode 100644 poincare/src/simplify/rules_generation/selector.cpp create mode 100644 poincare/src/simplify/rules_generation/selector.h diff --git a/poincare/src/simplify/expression_selector.cpp b/poincare/src/simplify/expression_selector.cpp index 93b65c6e4..8c7a90df9 100644 --- a/poincare/src/simplify/expression_selector.cpp +++ b/poincare/src/simplify/expression_selector.cpp @@ -3,7 +3,7 @@ extern "C" { #include } -int ExpressionSelector::match(Expression * e, Expression ** matches) { +int ExpressionSelector::match(Expression * e, ExpressionMatch ** matches) { int numberOfMatches = 0; // Does the current node match? @@ -23,7 +23,9 @@ int ExpressionSelector::match(Expression * e, Expression ** matches) { } // The current node does match. Let's add it to our matches - matches[numberOfMatches++] = e; + // FIXME + matches[numberOfMatches++] = ExpressionMatch(&e, 1); + //matches[numberOfMatches++] = e; // FIXME: For now we'll ignore the commutativity of the Selector // which is definitely something *very* important @@ -33,6 +35,15 @@ int ExpressionSelector::match(Expression * e, Expression ** matches) { ExpressionSelector * childSelector = this->child(i); // To account for commutativity, we should have multiple possibilities for childExpression Expression * childExpression = e->operand(i); + if (childSelector->m_match == ExpressionSelector::Match::WildCard) { + assert(i == m_numberOfChildren-1); // Wildcards should be the last argument! + Expression * pouet[255];//TODO + for (int j=i; jnumberOfOperands(); j++) { + pouet[j-i] = e->operand(j); + ExpressionMatch(e->operand(j...)); + } + matches[i+1] = ExpressionMatch(pouet, childSelector->numberOfOperands() - i +1); + } int numberOfChildMatches = childSelector->match(childExpression, (matches+numberOfMatches)); if (numberOfChildMatches == 0) { return 0; diff --git a/poincare/src/simplify/expression_selector.h b/poincare/src/simplify/expression_selector.h index 3274a565e..aa0044b52 100644 --- a/poincare/src/simplify/expression_selector.h +++ b/poincare/src/simplify/expression_selector.h @@ -2,6 +2,7 @@ #define POINCARE_SIMPLIFY_EXPRESSION_SELECTOR_H #include +#include "expression_match.h" extern "C" { #include } @@ -22,9 +23,8 @@ public: * Caution: This function *will* write to *matches even if the returned * value is zero. */ - // TODO Matches are weak pointers. - int match(Expression * e, Expression ** matches); // Return the matched expressions - /*Expression ** match(Expression * e);*/ + int match(Expression * e, ExpressionMatch ** matches); + Match m_match; union { // m_match == Any diff --git a/poincare/src/simplify/rules_generation/Makefile b/poincare/src/simplify/rules_generation/Makefile new file mode 100644 index 000000000..570b45fae --- /dev/null +++ b/poincare/src/simplify/rules_generation/Makefile @@ -0,0 +1,16 @@ +all: + bison --defines=rules_tokens.h rules_parser.y -o rules_parser.cpp + clang++ -c -std=c++11 rules_parser.cpp + flex -o rules_lexer.cpp rules_lexer.l + clang++ -c -std=c++11 rules_lexer.cpp + clang++ -c -std=c++11 rule.cpp + clang++ -c -std=c++11 builder.cpp + clang++ -c -std=c++11 selector.cpp + clang++ -c -std=c++11 node.cpp + clang++ rules_lexer.o rules_parser.o rule.o builder.o selector.o node.o -o parser + +run: + cat rule.pr | ./parser + +clean: + rm -f rules_token.h rules_lexer.cpp rules_parser.cpp parser *.o diff --git a/poincare/src/simplify/rules_generation/builder.cpp b/poincare/src/simplify/rules_generation/builder.cpp new file mode 100644 index 000000000..9397b4e47 --- /dev/null +++ b/poincare/src/simplify/rules_generation/builder.cpp @@ -0,0 +1,30 @@ +#include "builder.h" +#include "rule.h" +#include +#include + +Builder::Builder(Type type, std::string * name, std::vector * children) : + Node(name, (std::vector *)children), + m_type(type) +{ +} + +void Builder::generateFields(Rule * context, std::string &indentation) { + Selector * selector = context->selector(); + switch (m_type) { + case Type::ExpressionType: + std::cout << indentation << ".m_action = ExpressionBuilder::Action::BuildFromTypeAndValue," << std::endl; + std::cout << indentation << ".m_expressionType = Expression::Type::" << *m_name << std::endl; + break; + case Type::Variable: + std::cout << indentation << ".m_action = ExpressionBuilder::Action::Clone," << std::endl; + assert(m_children->size() == 0); + std::cout << indentation << ".m_matchIndex = " << selector->flatIndexOfChildNamed(*m_name) << std::endl; + break; + case Type::Wildcard: + std::cout << indentation << ".m_action = ExpressionBuilder::Action::BringUpWildcard," << std::endl; + assert(m_children->size() == 0); + std::cout << indentation << ".m_matchIndex = " << selector->flatIndexOfChildNamed(*m_name) << std::endl; + break; + } +} diff --git a/poincare/src/simplify/rules_generation/builder.h b/poincare/src/simplify/rules_generation/builder.h new file mode 100644 index 000000000..45c923273 --- /dev/null +++ b/poincare/src/simplify/rules_generation/builder.h @@ -0,0 +1,22 @@ +#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_BUILDER_H +#define POINCARE_SIMPLIFY_RULES_GENERATION_BUILDER_H + +#include "node.h" +#include + +class Builder : public Node { +public: + enum class Type { + ExpressionGenerator, + ExpressionType, + Variable, + Wildcard + }; + Builder(Type type, std::string * name, std::vector * children = nullptr); +protected: + void generateFields(Rule * context, std::string &indentation) override; +private: + Type m_type; +}; + +#endif diff --git a/poincare/src/simplify/rules_generation/node.cpp b/poincare/src/simplify/rules_generation/node.cpp new file mode 100644 index 000000000..d0b5869f3 --- /dev/null +++ b/poincare/src/simplify/rules_generation/node.cpp @@ -0,0 +1,67 @@ +#include "builder.h" +#include +#include + +Node::Node(std::string * name, std::vector * children) : + m_name(name), + m_children(children) +{ + if (children == nullptr) { + m_children = new std::vector(); + } +} + +Node::~Node() { + delete m_children; +} + +int Node::flatIndexOfChildNamed(std::string name) { + if (name == *m_name) { + return 0; + } + int sum=1; + for (Node * child : *m_children) { + int index = child->flatIndexOfChildNamed(name); + if (index >= 0) { + return sum+index; + } else { + sum += child->totalDescendantCountIncludingSelf(); + } + } + return -1; +} + +int Node::totalDescendantCountIncludingSelf() { + int result = 1; + for (Node * child : *m_children) { + result += child->totalDescendantCountIncludingSelf(); + } + return result; +} + +std::string indentation_string(int i) { + int indentBy = 2; + std::string result; + result.reserve(i*indentBy); + for (int j=0; jgenerateFields(context, nextIndentation); + std::cout << nextIndentation << ".m_numberOfChildren = " << m_children->size() << "," << std::endl; + std::cout << indentation << "}," << std::endl; + int generatedCount = 1; + for (Node * child : *m_children) { + generatedCount += child->generate(context, index+generatedCount, indentationLevel+1); + } + return generatedCount; +} diff --git a/poincare/src/simplify/rules_generation/node.h b/poincare/src/simplify/rules_generation/node.h new file mode 100644 index 000000000..2ecbe4e9f --- /dev/null +++ b/poincare/src/simplify/rules_generation/node.h @@ -0,0 +1,23 @@ +#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_NODE_H +#define POINCARE_SIMPLIFY_RULES_GENERATION_NODE_H + +class Rule; + +#include +#include + +class Node { +public: + Node(std::string * name, std::vector * m_children); + ~Node(); + int generate(Rule * context = nullptr, int index = 0, int indentationLevel = 0); + int totalDescendantCountIncludingSelf(); + int flatIndexOfChildNamed(std::string name); +protected: + virtual void generateFields(Rule * context, std::string &indentation) = 0; +protected: + std::string * m_name; + std::vector * m_children; +}; + +#endif diff --git a/poincare/src/simplify/rules_generation/rule.cpp b/poincare/src/simplify/rules_generation/rule.cpp new file mode 100644 index 000000000..e01f5d319 --- /dev/null +++ b/poincare/src/simplify/rules_generation/rule.cpp @@ -0,0 +1,25 @@ +#include "rule.h" +#include + +Rule::Rule(Selector * selector, Builder * builder) : + m_selector(selector), m_builder(builder) { +} + +Rule::~Rule() { + delete m_builder; + delete m_selector; +} + +Selector * Rule::selector() { + return m_selector; +} + +void Rule::generate(std::string rule_name) { + std::cout << "const ExpressionSelector " << rule_name << "Selector[" << m_selector->totalDescendantCountIncludingSelf() << "] = {" << std::endl; + m_selector->generate(this); + std::cout << "};" << std::endl; + + std::cout << "const ExpressionBuilder " << rule_name << "Builder[" << m_builder->totalDescendantCountIncludingSelf() << "] = {" << std::endl; + m_builder->generate(this); + std::cout << "};" << std::endl; +} diff --git a/poincare/src/simplify/rules_generation/rule.h b/poincare/src/simplify/rules_generation/rule.h new file mode 100644 index 000000000..de303e794 --- /dev/null +++ b/poincare/src/simplify/rules_generation/rule.h @@ -0,0 +1,18 @@ +#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_RULE_H +#define POINCARE_SIMPLIFY_RULES_GENERATION_RULE_H + +#include "selector.h" +#include "builder.h" + +class Rule { +public: + Rule(Selector * selector, Builder * builder); + ~Rule(); + void generate(std::string rule_name); + Selector * selector(); +private: + Selector * m_selector; + Builder * m_builder; +}; + +#endif diff --git a/poincare/src/simplify/rules_generation/rules_lexer.l b/poincare/src/simplify/rules_generation/rules_lexer.l new file mode 100644 index 000000000..748a688ce --- /dev/null +++ b/poincare/src/simplify/rules_generation/rules_lexer.l @@ -0,0 +1,22 @@ +%option noyywrap + +%{ + +#include "rule.h" +#include "rules_tokens.h" + +%} + +%% + +[A-Z][a-z]+ { yylval.string = new std::string(yytext); return(EXPRESSION_TYPE); } +\$[a-zA-Z]+ { yylval.string = new std::string(yytext); return(EXPRESSION_GENERATOR); } +[a-z]+\* { yylval.string = new std::string(yytext); return(WILDCARD); } +[a-z]+ { yylval.string = new std::string(yytext); return(VARIABLE); } +\-\> { return(SIMPLIFIES_TO); } +\( { return(LEFT_PARENTHESIS); } +\) { return(RIGHT_PARENTHESIS); } +\, { return(COMMA); } +\; { return(SEMICOLON); } + +%% diff --git a/poincare/src/simplify/rules_generation/rules_parser.y b/poincare/src/simplify/rules_generation/rules_parser.y new file mode 100644 index 000000000..1a7e4f06e --- /dev/null +++ b/poincare/src/simplify/rules_generation/rules_parser.y @@ -0,0 +1,130 @@ +/* This file should be built with Bison 3.0.4. It might work with other Bison + * version, but those haven't been tested. */ + +/* Our lexer and parser are reentrant. That means that their generated functions + * (such as yylex) will expect a context parameter, so let's tell Bison about + * it. Note that the context is an opaque pointer. */ + +/* When calling the parser, we will provide yyparse with an extra parameter : a + * backpointer to the resulting expression. */ +%parse-param { std::vector ** rules } + +%{ +#include "rule.h" + +int yylex(); +int yyparse(std::vector ** rules); +int yyerror(std::vector ** rules, char *s); +%} + + +/* All symbols (both terminals and non-terminals) may have a value associated + * with them. In our case, it's going to be either an Expression (for example, + * when parsing (a/b) we want to create a new Fraction), or a string (this will + * be useful to retrieve the value of Integers for example). */ +%union { + std::vector * builder_list; + std::vector * selector_list; + std::vector * rule_list; + Rule * rule; + Selector * selector; + Builder * builder; + std::string * string; +} + +/* The INTEGER token uses the "string" part of the union to store its value */ +%token INTEGER +%token SYMBOL + +%token EXPRESSION_TYPE +%token EXPRESSION_GENERATOR +%token WILDCARD +%token VARIABLE + +%token SIMPLIFIES_TO +%token LEFT_PARENTHESIS +%token RIGHT_PARENTHESIS +%token COMMA +%token SEMICOLON + +%type rule_list; +%type rule; +%type selector; +%type selector_list; +%type builder; +%type builder_list; + +/* The "exp" symbol uses the "expression" part of the union. */ +/*%type exp;*/ + +%% + +root: + rule_list { *rules = $1; } + +rule_list: + rule { $$ = new std::vector(); $$->push_back($1); } + | rule_list rule { $1->push_back($2); $$ = $1; } + +rule: + selector SIMPLIFIES_TO builder SEMICOLON { $$ = new Rule($1, $3); } + +selector: + VARIABLE { $$ = new Selector(Selector::Type::Variable, $1); } + | WILDCARD { $$ = new Selector(Selector::Type::Wildcard, $1); } + | EXPRESSION_TYPE LEFT_PARENTHESIS selector_list RIGHT_PARENTHESIS { + $$ = new Selector(Selector::Type::ExpressionType, $1, $3); + } + +selector_list: + selector { $$ = new std::vector(); $$->push_back($1); } + | selector_list COMMA selector { $1->push_back($3); $$ = $1; } + +builder: + VARIABLE { $$ = new Builder(Builder::Type::Variable, $1); } + | WILDCARD { $$ = new Builder(Builder::Type::Wildcard, $1); } + | EXPRESSION_GENERATOR LEFT_PARENTHESIS builder_list RIGHT_PARENTHESIS { + $$ = new Builder(Builder::Type::ExpressionGenerator, $1, $3); + } + | EXPRESSION_TYPE LEFT_PARENTHESIS builder_list RIGHT_PARENTHESIS { + $$ = new Builder(Builder::Type::ExpressionType, $1, $3); + } + +builder_list: + builder { $$ = new std::vector(); $$->push_back($1); } + | builder_list COMMA builder { $1->push_back($3); $$ = $1; } + +%% + +#include +#include + +int yyerror(std::vector ** rules, char *s) { + printf("Error: %s\n",s); + return 0; +} + +int main(void) { + std::vector * rules = new std::vector(); + yyparse(&rules); + int counter = 0; + for (int i=0; isize(); i++) { + std::stringstream name; + name << "rule" << i; + rules->at(i)->generate(name.str()); + std::cout << std::endl; + } + std::cout << "const Simplification simplifications[" << rules->size() << "] = {" << std::endl; + for (int i=0; isize(); i++) { + std::stringstream name; + name << "rule" << i; + std::cout << " {" << std::endl; + std::cout << " .m_selector = (ExpressionSelector *)" << name.str() << "Selector," << std::endl; + std::cout << " .m_builder = (ExpressionBuilder *)" << name.str() << "Builder," << std::endl; + std::cout << " }," << std::endl; + } + std::cout << "};" << std::endl; + + delete rules; + return 0; +} diff --git a/poincare/src/simplify/rules_generation/selector.cpp b/poincare/src/simplify/rules_generation/selector.cpp new file mode 100644 index 000000000..b9ec4a532 --- /dev/null +++ b/poincare/src/simplify/rules_generation/selector.cpp @@ -0,0 +1,24 @@ +#include "selector.h" +#include +#include + +Selector::Selector(Type type, std::string * name, std::vector * children) : + Node(name, (std::vector *)children), + m_type(type) +{ +} + +void Selector::generateFields(Rule * context, std::string &indentation) { + switch (m_type) { + case Type::Variable: + std::cout << indentation << ".m_match = ExpressionSelector::Match::Any," << std::endl; + break; + case Type::Wildcard: + std::cout << indentation << ".m_match = ExpressionSelector::Match::Wildcard," << std::endl; + break; + case Type::ExpressionType: + std::cout << indentation << ".m_match = ExpressionSelector::Match::TypeAndValue," << std::endl; + std::cout << indentation << ".m_expressionType = Expression::Type::" << *m_name << "," << std::endl; + break; + } +} diff --git a/poincare/src/simplify/rules_generation/selector.h b/poincare/src/simplify/rules_generation/selector.h new file mode 100644 index 000000000..730610e62 --- /dev/null +++ b/poincare/src/simplify/rules_generation/selector.h @@ -0,0 +1,21 @@ +#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_SELECTOR_H +#define POINCARE_SIMPLIFY_RULES_GENERATION_SELECTOR_H + +#include "node.h" +#include + +class Selector : public Node { +public: + enum class Type { + Variable, + Wildcard, + ExpressionType + }; + Selector(Type type, std::string * name, std::vector * children = nullptr); +protected: + void generateFields(Rule * context, std::string &indentation) override; +private: + Type m_type; +}; + +#endif diff --git a/poincare/src/simplify/simplification.cpp b/poincare/src/simplify/simplification.cpp index f344b4c35..50900f3d1 100644 --- a/poincare/src/simplify/simplification.cpp +++ b/poincare/src/simplify/simplification.cpp @@ -1,7 +1,7 @@ #include "simplification.h" Expression * Simplification::simplify(Expression * expression) const { - Expression * matches[255]; // FIXME: The sized ca be given by our compiler + ExpressionMatch * matches[255]; // FIXME: The size ca be given by our compiler if (m_selector->match(expression, matches)) { if (expression->numberOfOperands() == m_selector->m_numberOfChildren) { return m_builder->build(matches);