mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 13:50:28 +01:00
Poincare: Add a Simplification rule generator
Change-Id: I4a0971405164c40c5ca3f7e1a0406f01d83d67d8
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
16
poincare/src/simplify/rules_generation/Makefile
Normal file
16
poincare/src/simplify/rules_generation/Makefile
Normal 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
|
||||
30
poincare/src/simplify/rules_generation/builder.cpp
Normal file
30
poincare/src/simplify/rules_generation/builder.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
22
poincare/src/simplify/rules_generation/builder.h
Normal file
22
poincare/src/simplify/rules_generation/builder.h
Normal 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
|
||||
67
poincare/src/simplify/rules_generation/node.cpp
Normal file
67
poincare/src/simplify/rules_generation/node.cpp
Normal 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;
|
||||
}
|
||||
23
poincare/src/simplify/rules_generation/node.h
Normal file
23
poincare/src/simplify/rules_generation/node.h
Normal 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
|
||||
25
poincare/src/simplify/rules_generation/rule.cpp
Normal file
25
poincare/src/simplify/rules_generation/rule.cpp
Normal 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;
|
||||
}
|
||||
18
poincare/src/simplify/rules_generation/rule.h
Normal file
18
poincare/src/simplify/rules_generation/rule.h
Normal 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
|
||||
22
poincare/src/simplify/rules_generation/rules_lexer.l
Normal file
22
poincare/src/simplify/rules_generation/rules_lexer.l
Normal 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); }
|
||||
|
||||
%%
|
||||
130
poincare/src/simplify/rules_generation/rules_parser.y
Normal file
130
poincare/src/simplify/rules_generation/rules_parser.y
Normal 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;
|
||||
}
|
||||
24
poincare/src/simplify/rules_generation/selector.cpp
Normal file
24
poincare/src/simplify/rules_generation/selector.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
21
poincare/src/simplify/rules_generation/selector.h
Normal file
21
poincare/src/simplify/rules_generation/selector.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user