Poincare: Add a Simplification rule generator

Change-Id: I4a0971405164c40c5ca3f7e1a0406f01d83d67d8
This commit is contained in:
Romain Goyet
2016-03-31 18:47:18 +02:00
parent 7ddd1fc112
commit 6232079f02
14 changed files with 415 additions and 6 deletions

View File

@@ -3,7 +3,7 @@ extern "C" {
#include <assert.h>
}
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; j<childSelector->numberOfOperands(); 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;

View File

@@ -2,6 +2,7 @@
#define POINCARE_SIMPLIFY_EXPRESSION_SELECTOR_H
#include <poincare/expression.h>
#include "expression_match.h"
extern "C" {
#include <stdint.h>
}
@@ -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

View File

@@ -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

View File

@@ -0,0 +1,30 @@
#include "builder.h"
#include "rule.h"
#include <iostream>
#include <cassert>
Builder::Builder(Type type, std::string * name, std::vector<Builder *> * children) :
Node(name, (std::vector<Node *> *)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;
}
}

View File

@@ -0,0 +1,22 @@
#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_BUILDER_H
#define POINCARE_SIMPLIFY_RULES_GENERATION_BUILDER_H
#include "node.h"
#include <string>
class Builder : public Node {
public:
enum class Type {
ExpressionGenerator,
ExpressionType,
Variable,
Wildcard
};
Builder(Type type, std::string * name, std::vector<Builder *> * children = nullptr);
protected:
void generateFields(Rule * context, std::string &indentation) override;
private:
Type m_type;
};
#endif

View File

@@ -0,0 +1,67 @@
#include "builder.h"
#include <iostream>
#include <cassert>
Node::Node(std::string * name, std::vector<Node *> * children) :
m_name(name),
m_children(children)
{
if (children == nullptr) {
m_children = new std::vector<Node *>();
}
}
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; j<i; j++) {
for (int k=0; k<indentBy; k++) {
result += " ";
}
}
return result;
}
int Node::generate(Rule * context, int index, int indentationLevel) {
std::string indentation = indentation_string(indentationLevel);
std::string nextIndentation = indentation_string(indentationLevel+1);
std::cout << indentation << "{" << std::endl;
std::cout << nextIndentation << "// #" << index << std::endl;
this->generateFields(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;
}

View File

@@ -0,0 +1,23 @@
#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_NODE_H
#define POINCARE_SIMPLIFY_RULES_GENERATION_NODE_H
class Rule;
#include <vector>
#include <string>
class Node {
public:
Node(std::string * name, std::vector<Node *> * 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<Node *> * m_children;
};
#endif

View File

@@ -0,0 +1,25 @@
#include "rule.h"
#include <iostream>
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;
}

View File

@@ -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

View File

@@ -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); }
%%

View File

@@ -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<Rule *> ** rules }
%{
#include "rule.h"
int yylex();
int yyparse(std::vector<Rule *> ** rules);
int yyerror(std::vector<Rule *> ** 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 *> * builder_list;
std::vector<Selector *> * selector_list;
std::vector<Rule *> * 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 <string> INTEGER
%token <string> SYMBOL
%token <string> EXPRESSION_TYPE
%token <string> EXPRESSION_GENERATOR
%token <string> WILDCARD
%token <string> VARIABLE
%token SIMPLIFIES_TO
%token LEFT_PARENTHESIS
%token RIGHT_PARENTHESIS
%token COMMA
%token SEMICOLON
%type <rule_list> rule_list;
%type <rule> rule;
%type <selector> selector;
%type <selector_list> selector_list;
%type <builder> builder;
%type <builder_list> builder_list;
/* The "exp" symbol uses the "expression" part of the union. */
/*%type <expression> exp;*/
%%
root:
rule_list { *rules = $1; }
rule_list:
rule { $$ = new std::vector<Rule *>(); $$->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<Selector *>(); $$->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<Builder *>(); $$->push_back($1); }
| builder_list COMMA builder { $1->push_back($3); $$ = $1; }
%%
#include <sstream>
#include <iostream>
int yyerror(std::vector<Rule *> ** rules, char *s) {
printf("Error: %s\n",s);
return 0;
}
int main(void) {
std::vector<Rule *> * rules = new std::vector<Rule *>();
yyparse(&rules);
int counter = 0;
for (int i=0; i<rules->size(); 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; i<rules->size(); 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;
}

View File

@@ -0,0 +1,24 @@
#include "selector.h"
#include <iostream>
#include <cassert>
Selector::Selector(Type type, std::string * name, std::vector<Selector *> * children) :
Node(name, (std::vector<Node *> *)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;
}
}

View File

@@ -0,0 +1,21 @@
#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_SELECTOR_H
#define POINCARE_SIMPLIFY_RULES_GENERATION_SELECTOR_H
#include "node.h"
#include <string>
class Selector : public Node {
public:
enum class Type {
Variable,
Wildcard,
ExpressionType
};
Selector(Type type, std::string * name, std::vector<Selector *> * children = nullptr);
protected:
void generateFields(Rule * context, std::string &indentation) override;
private:
Type m_type;
};
#endif

View File

@@ -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);