[Poincare] Handle symbol/context

This commit is contained in:
Romain Goyet
2015-11-18 22:31:21 +01:00
parent aa783df6f2
commit 15d91052f2
22 changed files with 213 additions and 101 deletions

View File

@@ -34,14 +34,17 @@ void draw_lines_from_center() {
}
}
void plot(Expression * e, Variable * v, float xMin, float xMax, float yMin, float yMax) {
void plot(Expression * e, float xMin, float xMax, float yMin, float yMax) {
Context plotContext;
KDCoordinate screenWidth = 240;
KDCoordinate screenHeight = 160;
KDPoint previousPoint;
for (KDCoordinate i=0;i<screenWidth; i++) {
float x = xMin + (xMax-xMin)/screenWidth*i;
v->setValue(x);
float y = e->approximate();
Float xExp = Float(x);
//plotContext["x"] = xExp;
plotContext.setExpressionForSymbolName(&xExp, "x");
float y = e->approximate(plotContext);
KDCoordinate j = ((y-yMin)/(yMax-yMin)*screenHeight);
KDPoint currentPoint = KDPointMake(i,screenHeight-j);
if (i>0) {
@@ -53,8 +56,7 @@ void plot(Expression * e, Variable * v, float xMin, float xMax, float yMin, floa
void funnyPlot() {
Expression * e = Expression::parse("1/x");
Variable * v = Variable::VariableNamed("x");
plot(e,v, 1.0f, 4.0f, 0.0f, 1.0f);
plot(e, 1.0f, 4.0f, 0.0f, 1.0f);
delete e;
}
@@ -91,10 +93,7 @@ void interactive_expression_parsing() {
ExpressionLayout * l = e->createLayout(nullptr);
if (l) {
l->draw(KDPointMake(0,100));
Variable * v = Variable::VariableNamed("x");
if (v) {
plot(e,v, 0.0f, 3.0f, 0.0f, 2.0f);
}
plot(e, 0.0f, 3.0f, 0.0f, 2.0f);
delete l;
}
delete e;

View File

@@ -1,5 +1,5 @@
SFLAGS += -Ipoincare/include
objs += $(addprefix poincare/src/, addition.o expression.o integer.o fraction.o expression_lexer.o expression_parser.o variable.o)
objs += $(addprefix poincare/src/, addition.o context.o expression.o float.o integer.o fraction.o expression_lexer.o expression_parser.o product.o symbol.o)
objs += $(addprefix poincare/src/layout/, expression_layout.o fraction_layout.o horizontal_layout.o string_layout.o)
tests += $(addprefix poincare/test/, integer.cpp)

View File

@@ -2,10 +2,13 @@
#define POINCARE_H
#include <poincare/addition.h>
#include <poincare/context.h>
#include <poincare/expression.h>
#include <poincare/fraction.h>
#include <poincare/float.h>
#include <poincare/integer.h>
#include <poincare/power.h>
#include <poincare/variable.h>
#include <poincare/product.h>
#include <poincare/symbol.h>
#endif

View File

@@ -8,7 +8,7 @@ class Addition : public Expression {
Addition(Expression * first_operand, Expression * second_operand);
~Addition();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate() override;
float approximate(Context& context) override;
private:
Expression * m_children[2];
};

View File

@@ -0,0 +1,26 @@
#ifndef POINCARE_CONTEXT_H
#define POINCARE_CONTEXT_H
#include <poincare/expression.h>
//TODO: We should probably make a COPY of the expressions we store
class Context {
public:
Context();
~Context();
Expression * operator[](const char * symbol_name) const;
void setExpressionForSymbolName(Expression * expression, const char * symbol_name);
/*
Expression const& operator[](const char * symbol_name) const;
Expression& operator[](const char * symbol_name);
*/
private:
struct ContextPair {
const char * name;
Expression * expression;
};
ContextPair * m_pairs;
};
#endif

View File

@@ -4,6 +4,8 @@
#include <poincare/expression_layout.h>
#include <kandinsky.h>
class Context;
class Expression {
public:
static Expression * parse(char * string);
@@ -19,7 +21,7 @@ class Expression {
//virtual bool identicalTo(Expression * e);
//virtual Expression * simplify();
virtual float approximate() = 0;
virtual float approximate(Context& context) = 0;
/*private:
void forEachChild(ExpressionAction);
*/

View File

@@ -0,0 +1,17 @@
#ifndef POINCARE_FLOAT_H
#define POINCARE_FLOAT_H
#include <poincare/expression.h>
class Float : public Expression {
public:
Float(float f);
~Float();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
private:
float m_float;
};
#endif

View File

@@ -8,7 +8,7 @@ class Fraction : public Expression {
Fraction(Expression * numerator, Expression * denominator);
~Fraction();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate() override;
float approximate(Context& context) override;
private:
Expression * m_numerator;
Expression * m_denominator;

View File

@@ -31,15 +31,15 @@ class Integer : public Expression {
virtual bool identicalTo(Expression * e);
*/
virtual ExpressionLayout * createLayout(ExpressionLayout * parent);
virtual float approximate();
virtual float approximate(Context& context);
private:
int8_t ucmp(const Integer &other) const; // -1, 0, or 1
Integer usum(const Integer &other, bool subtract, bool output_negative) const;
Integer add(const Integer &other, bool inverse_other_negative) const;
/* WARNING: This constructor takes ownership of the bits array and will free it! */
Integer(native_uint_t * digits, uint16_t numberOfDigits, bool negative);
uint16_t m_numberOfDigits; // In base native_uint_max
native_uint_t * m_digits; // LITTLE-ENDIAN
uint16_t m_numberOfDigits; // In base native_uint_max
bool m_negative;
/*
// TODO: Small-int optimization

View File

@@ -0,0 +1,16 @@
#ifndef POINCARE_PRODUCT_H
#define POINCARE_PRODUCT_H
#include <poincare/expression.h>
class Product : public Expression {
public:
Product(Expression * first_factor, Expression * second_factor);
~Product();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
private:
Expression * m_children[2];
};
#endif

View File

@@ -0,0 +1,16 @@
#ifndef POINCARE_SYMBOL_H
#define POINCARE_SYMBOL_H
#include <poincare/expression.h>
class Symbol : public Expression {
public:
Symbol(char * name);
~Symbol();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
private:
char * m_name;
};
#endif

View File

@@ -1,21 +0,0 @@
#ifndef POINCARE_VARIABLE_H
#define POINCARE_VARIABLE_H
#include <poincare/expression.h>
class Variable : public Expression {
public:
Variable(char * name);
~Variable();
static Variable * VariableNamed(char * name);
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate() override;
void setValue(float value);
private:
static void RegisterVariable(Variable * v);
static void UnregisterVariable(Variable * v);
char * m_name;
float m_value;
};
#endif

View File

@@ -11,8 +11,8 @@ Addition::~Addition() {
delete m_children[0];
}
float Addition::approximate() {
return m_children[0]->approximate() + m_children[1]->approximate();
float Addition::approximate(Context& context) {
return m_children[0]->approximate(context) + m_children[1]->approximate(context);
}
ExpressionLayout * Addition::createLayout(ExpressionLayout * parent) {

45
poincare/src/context.cpp Normal file
View File

@@ -0,0 +1,45 @@
#include <poincare/context.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CONTEXT_PAIRS 10
Context::Context() {
size_t size = sizeof(ContextPair)*MAX_CONTEXT_PAIRS;
m_pairs = (ContextPair *)malloc(size);
memset(m_pairs, 0, size);
}
Context::~Context() {
free(m_pairs);
}
Expression * Context::operator[](const char * symbol_name) const {
for (int16_t i=0; i<MAX_CONTEXT_PAIRS; i++) {
ContextPair p = m_pairs[i];
if (p.name != NULL && strcmp(p.name, symbol_name) == 0) {
return p.expression;
}
}
return nullptr;
}
void Context::setExpressionForSymbolName(Expression * expression, const char * symbol_name) {
for (int16_t i=0; i<MAX_CONTEXT_PAIRS; i++) {
ContextPair * p = &m_pairs[i];
if (p->name == NULL) {
// FIXME: Should be copied or retained!
// What follows is *ugly*
p->name = symbol_name;
p->expression = expression;
return;
} else if (strcmp(p->name, symbol_name) == 0) {
// FIXME: Release, retain
// What follows is *awful*
p->expression = expression;
return;
}
}
// Hu-oh, no more space!
abort();
}

View File

@@ -50,6 +50,7 @@
[0-9]+ { yylval->string = yytext; return(INTEGER); }
\/ { return(DIVIDE); }
\* { return(MULTIPLY); }
\^ { return(POW); }
\+ { return(PLUS); }
[A-Za-z]+ { yylval->string = yytext; return(SYMBOL); }

View File

@@ -59,6 +59,7 @@ void poincare_expression_yyerror(yyscan_t scanner, Expression ** expressionOutpu
/* The DIVIDE and POW tokens use no value */
%token DIVIDE
%token MULTIPLY
%token POW
%token PLUS
@@ -92,10 +93,11 @@ Root:
}
exp:
INTEGER { $$ = new Integer($1); }
| SYMBOL { $$ = new Variable($1); }
| exp DIVIDE exp { $$ = new Fraction($1,$3); }
| exp PLUS exp { $$ = new Addition($1,$3); }
INTEGER { $$ = new Integer($1); }
| SYMBOL { $$ = new Symbol($1); }
| exp DIVIDE exp { $$ = new Fraction($1,$3); }
| exp MULTIPLY exp { $$ = new Product($1,$3); }
| exp PLUS exp { $$ = new Addition($1,$3); }
/* | exp POW exp { $$ = new Power($1,$3); } */
;

17
poincare/src/float.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include <poincare/float.h>
#include <assert.h>
Float::Float(float f) : m_float(f) {
}
Float::~Float() {
}
float Float::approximate(Context& context) {
return m_float;
}
ExpressionLayout * Float::createLayout(ExpressionLayout * parent) {
assert(0); // Should not come here, ever...
return nullptr;
}

View File

@@ -16,7 +16,7 @@ ExpressionLayout * Fraction::createLayout(ExpressionLayout * parent) {
return new FractionLayout(parent, m_numerator, m_denominator);
}
float Fraction::approximate() {
float Fraction::approximate(Context& context) {
// TODO: handle division by zero
return m_numerator->approximate()/m_denominator->approximate();
return m_numerator->approximate(context)/m_denominator->approximate(context);
}

View File

@@ -270,7 +270,7 @@ Integer Integer::operator/(const Integer &other) const {
return Division(*this, other).m_quotient;
}
float Integer::approximate() {
float Integer::approximate(Context& context) {
union {
uint32_t uint_result;
float float_result;

20
poincare/src/product.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include <poincare/product.h>
#include "layout/horizontal_layout.h"
Product::Product(Expression * first_factor, Expression * second_factor) {
m_children[0] = first_factor;
m_children[1] = second_factor;
}
Product::~Product() {
delete m_children[1];
delete m_children[0];
}
float Product::approximate(Context& context) {
return m_children[0]->approximate(context) * m_children[1]->approximate(context);
}
ExpressionLayout * Product::createLayout(ExpressionLayout * parent) {
return new HorizontalLayout(parent, m_children[0], '*', m_children[1]);
}

24
poincare/src/symbol.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include <poincare/symbol.h>
#include <poincare/context.h>
#include <stdlib.h>
#include "layout/string_layout.h"
Symbol::Symbol(char * name) {
size_t length = strlen(name);
m_name = (char *)malloc(sizeof(char)*length+1);
memcpy(m_name, name, length);
m_name[length] = 0;
}
Symbol::~Symbol() {
free(m_name);
}
float Symbol::approximate(Context& context) {
return context[m_name]->approximate(context);
}
ExpressionLayout * Symbol::createLayout(ExpressionLayout * parent) {
size_t length = strlen(m_name);
return new StringLayout(parent, m_name, length);
}

View File

@@ -1,55 +0,0 @@
#include <poincare/variable.h>
#include <stdlib.h>
#include "layout/string_layout.h"
Variable ** sRegisteredVariables = NULL;
int16_t sRegisteredVariableCount = 0;
#define MAX_REGISTERED_VARIABLES 10
Variable::Variable(char * name) :
m_value(0.0f) {
size_t length = strlen(name);
m_name = (char *)malloc(sizeof(char)*length+1);
memcpy(m_name, name, length);
m_name[length] = 0;
RegisterVariable(this);
}
Variable::~Variable() {
UnregisterVariable(this);
free(m_name);
}
float Variable::approximate() {
return m_value;
}
ExpressionLayout * Variable::createLayout(ExpressionLayout * parent) {
size_t length = strlen(m_name);
return new StringLayout(parent, m_name, length);
}
Variable * Variable::VariableNamed(char * name) {
for (int16_t i=0; i<sRegisteredVariableCount; i++) {
Variable * currentVariable = sRegisteredVariables[i];
if (strcmp(currentVariable->m_name, name) == 0) {
return currentVariable;
}
}
return NULL;
}
void Variable::setValue(float value) {
m_value = value;
}
void Variable::RegisterVariable(Variable * v) {
if (sRegisteredVariables == NULL) {
sRegisteredVariables = (Variable **)malloc(MAX_REGISTERED_VARIABLES*sizeof(Variable *));
}
sRegisteredVariables[sRegisteredVariableCount++] = v;
}
void Variable::UnregisterVariable(Variable * v) {
// TODO!
}