Merge branch 'master' of ssh://git.numworks.com:29418/CalcOS

Change-Id: Ic13da71a80ab823ee0b11f550ee359c4032edc36
This commit is contained in:
Romain Goyet
2016-03-25 11:53:59 +01:00
27 changed files with 327 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
app_objs += $(addprefix app/,\
app.o\
text_input.o)
utils.o)
products += $(app_objs) app.elf app.hex app.bin
app.elf: $(app_objs)

View File

@@ -6,7 +6,7 @@ extern "C" {
#include <poincare.h>
#include "text_input.h"
#include "utils.h"
void draw_lines_from_center() {
KDCoordinate width = SCREEN_WIDTH;
@@ -60,16 +60,6 @@ void funnyPlot() {
delete e;
}
static void clear_screen() {
KDRect r;
r.x = 0;
r.y = 0;
r.width = SCREEN_WIDTH;
r.height = SCREEN_HEIGHT;
KDFillRect(r, 0x00);
}
static void interactive_expression_parsing() {
while (1) {
char * text_input = get_text();

View File

@@ -7,6 +7,15 @@ extern "C" {
#define PROMPT_HEIGHT 30
void clear_screen() {
KDRect r;
r.x = 0;
r.y = 0;
r.width = SCREEN_WIDTH;
r.height = SCREEN_HEIGHT;
KDFillRect(r, 0x00);
}
static void clear_prompt() {
KDRect r;
r.x = 0;

View File

@@ -1,8 +1,10 @@
#ifndef APP_TEXTINPUT_H
#define APP_TEXTINPUT_H
#ifndef APP_UTILS_H
#define APP_UTILS_H
/* Returns a pointer to an input text, allocated by the functions (it is thus
* the caller's role to free it). */
char* get_text();
#endif // APP_TEXTINPUT_H
void clear_screen();
#endif // APP_UTILS_H

View File

@@ -4,23 +4,28 @@ objs += $(addprefix poincare/src/,\
binary_operation.o\
commutative_operation.o\
context.o\
cosine.o\
expression.o\
expression_lexer.o\
expression_parser.o\
float.o\
fraction.o\
function.o\
integer.o\
leaf_expression.o\
power.o\
product.o\
sine.o\
subtraction.o\
symbol.o\
tangent.o\
)
objs += $(addprefix poincare/src/layout/,\
exponent_layout.o\
expression_layout.o\
fraction_layout.o\
function_layout.o\
horizontal_layout.o\
exponent_layout.o\
string_layout.o\
)
objs += $(addprefix poincare/src/simplify/,\
@@ -35,6 +40,7 @@ tests += $(addprefix poincare/test/,\
product.cpp\
simplify.cpp\
simplify_addition_integer.cpp\
trigo.cpp\
subtraction.cpp\
)

View File

@@ -3,13 +3,17 @@
#include <poincare/addition.h>
#include <poincare/context.h>
#include <poincare/cosine.h>
#include <poincare/expression.h>
#include <poincare/fraction.h>
#include <poincare/float.h>
#include <poincare/fraction.h>
#include <poincare/function.h>
#include <poincare/integer.h>
#include <poincare/power.h>
#include <poincare/product.h>
#include <poincare/sine.h>
#include <poincare/subtraction.h>
#include <poincare/symbol.h>
#include <poincare/tangent.h>
#endif

View File

@@ -0,0 +1,14 @@
#ifndef POINCARE_COSINE_H
#define POINCARE_COSINE_H
#include <poincare/function.h>
class Cosine : public Function {
public:
Cosine(Expression * arg, bool clone_arg=true): Function(arg, (char*) "cos", clone_arg) {}
float approximate(Context& context) override;
Type type() override;
Expression * clone() override;
};
#endif

View File

@@ -10,13 +10,16 @@ class Expression {
public:
enum class Type : uint8_t {
Addition,
Cosine,
Float,
Fraction,
Integer,
Power,
Product,
Sine,
Subtraction,
Symbol
Symbol,
Tangent,
};
static Expression * parse(char const * string);
virtual ~Expression();

View File

@@ -0,0 +1,19 @@
#ifndef POINCARE_FUNCTION_H
#define POINCARE_FUNCTION_H
#include <poincare/expression.h>
class Function : public Expression {
public:
Function(Expression * arg, char* function_name, bool clone_operands=true);
~Function();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
Expression * operand(int i) override;
int numberOfOperands() override;
protected:
Expression * m_arg;
private:
char* m_function_name;
};
#endif

View File

@@ -0,0 +1,14 @@
#ifndef POINCARE_SINE_H
#define POINCARE_SINE_H
#include <poincare/function.h>
class Sine : public Function {
public:
Sine(Expression * arg, bool clone_arg=true): Function(arg, (char*) "sin", clone_arg) {}
float approximate(Context& context) override;
Type type() override;
Expression * clone() override;
};
#endif

View File

@@ -0,0 +1,14 @@
#ifndef POINCARE_TANGENT_H
#define POINCARE_TANGENT_H
#include <poincare/function.h>
class Tangent : public Function {
public:
Tangent(Expression * arg, bool clone_arg=true): Function(arg, (char*) "tan", clone_arg) {}
float approximate(Context& context) override;
Type type() override;
Expression * clone() override;
};
#endif

View File

@@ -14,6 +14,5 @@ float Addition::operateApproximatevelyOn(float a, float b) {
}
ExpressionLayout * Addition::createLayout(ExpressionLayout * parent) {
//FIXME: There can be more than two operands now! :-)
return new HorizontalLayout(parent, operand(0), '+', operand(1));
return new HorizontalLayout(parent, m_operands, m_numberOfOperands, '+');
}

View File

@@ -30,6 +30,7 @@ int CommutativeOperation::numberOfOperands() {
}
Expression * CommutativeOperation::operand(int i) {
assert(i < m_numberOfOperands);
return m_operands[i];
}

15
poincare/src/cosine.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include <poincare/cosine.h>
#include "layout/horizontal_layout.h"
Expression * Cosine::clone() {
return new Cosine(m_arg, true);
}
Expression::Type Cosine::type() {
return Expression::Type::Cosine;
}
float Cosine::approximate(Context& context) {
// FIXME: use cosine obviously.
return m_arg->approximate(context);
}

View File

@@ -42,6 +42,9 @@ class Expression;
%%
[0-9]+ { yylval->string = yytext; return(INTEGER); }
sin {return(SINE);}
cos {return(COSINE);}
tan {return(TANGENT);}
[A-Za-z]+ { yylval->string = yytext; return(SYMBOL); }
\+ { return(PLUS); }
\- { return(MINUS); }

View File

@@ -54,6 +54,9 @@ void poincare_expression_yyerror(void * scanner, Expression ** expressionOutput,
%token MULTIPLY
%token DIVIDE
%token POW
%token SINE
%token COSINE
%token TANGENT
%token LEFT_PARENTHESIS
%token RIGHT_PARENTHESIS
@@ -85,6 +88,9 @@ exp:
| exp DIVIDE exp { Expression * terms[2] = {$1,$3}; $$ = new Fraction(terms, false); }
| exp POW exp { Expression * terms[2] = {$1,$3}; $$ = new Power(terms, false); }
| LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = $2; }
| SINE LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Sine($3); }
| COSINE LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Cosine($3); }
| TANGENT LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Tangent($3); }
;
%%

35
poincare/src/function.cpp Normal file
View File

@@ -0,0 +1,35 @@
extern "C" {
#include <stdlib.h>
}
#include <poincare/function.h>
#include "layout/function_layout.h"
Function::Function(Expression * arg, char* function_name, bool clone_operands) {
m_arg = (Expression *)malloc(sizeof(Expression));
m_function_name = function_name;
if (clone_operands) {
m_arg = arg->clone();
} else {
m_arg = arg;
}
}
Function::~Function() {
delete m_arg;
}
ExpressionLayout * Function::createLayout(ExpressionLayout * parent) {
return new FunctionLayout(parent, m_function_name, m_arg);
}
Expression * Function::operand(int i) {
if (i==0) {
return m_arg;
} else {
return nullptr;
}
}
int Function::numberOfOperands() {
return 1;
}

View File

@@ -0,0 +1,73 @@
extern "C" {
#include <kandinsky.h>
#include <assert.h>
}
#include "function_layout.h"
#include "string_layout.h"
// This code seems like a duplicate of the horizontal layout but it isn't, indeed the horizontal
// layout is used to print the same operation applied to different expressions such that:
// "expr_1 + epr_2 + expr_3 + expr_4".
// Here we want the pattern
// FUNCTION_NAME(expr).
// Thus the code in horizontal layer is not really reusable.
FunctionLayout::FunctionLayout(ExpressionLayout * parent, char* function_name, Expression * argument) :
ExpressionLayout(parent) {
m_children[0] = new StringLayout(this, function_name, 1);
char string[2] = {'(', '\0'};
m_children[1] = new StringLayout(this, string, 1);
m_children[2] = argument->createLayout(this);
string[0] = ')';
m_children[3] = new StringLayout(this, string, 1);
}
FunctionLayout::~FunctionLayout() {
for (int i(0); i<4; i++) {
delete m_children[i];
}
}
void FunctionLayout::render(KDPoint point) { }
KDSize FunctionLayout::computeSize() {
KDSize size = (KDSize){.width = 0, .height = 0};
int i = 0;
while (ExpressionLayout * c = child(i++)) {
KDSize childSize = c->size();
size.width += childSize.width;
if (childSize.height > size.height) {
size.height = childSize.height;
}
}
return size;
}
ExpressionLayout * FunctionLayout::child(uint16_t index) {
if (index >= 4) {
return nullptr;
}
return m_children[index];
}
KDPoint FunctionLayout::positionOfChild(ExpressionLayout * child) {
KDPoint position = (KDPoint){.x = 0, .y = 0};
uint16_t index = 0;
for (int i=0;i<4;i++) {
if (m_children[i] == child) {
index = i;
break;
}
}
if (index > 0) {
ExpressionLayout * previousChild = m_children[index-1];
assert(previousChild != nullptr);
position.x = previousChild->origin().x + previousChild->size().width;
}
position.y = (size().height - child->size().height)/2;
return position;
}

View File

@@ -0,0 +1,21 @@
#ifndef POINCARE_FUNCTION_LAYOUT_H
#define POINCARE_FUNCTION_LAYOUT_H
#include <poincare/expression.h>
#include <poincare/expression_layout.h>
class FunctionLayout : public ExpressionLayout {
public:
FunctionLayout(ExpressionLayout * parent, char* function_name, Expression * arg);
~FunctionLayout();
protected:
void render(KDPoint point) override;
KDSize computeSize() override;
ExpressionLayout * child(uint16_t index) override;
KDPoint positionOfChild(ExpressionLayout * child) override;
private:
ExpressionLayout * m_children[4];
};
#endif

View File

@@ -1,29 +1,31 @@
extern "C" {
#include <kandinsky.h>
#include <assert.h>
#include <kandinsky.h>
#include <stdlib.h>
}
#include "horizontal_layout.h"
#include "string_layout.h"
HorizontalLayout::HorizontalLayout(ExpressionLayout * parent, Expression * left_expression, char symbol, Expression * right_expression) :
ExpressionLayout(parent ) {
m_children[0] = left_expression->createLayout(this);
HorizontalLayout::HorizontalLayout(ExpressionLayout * parent, Expression ** operands,int number_of_operands, char symbol) : ExpressionLayout(parent) {
assert(number_of_operands > 0);
m_number_of_children = 2*number_of_operands-1;
m_children_layouts = (ExpressionLayout **)malloc(m_number_of_children*sizeof(ExpressionLayout *));
char string[2] = {symbol, '\0'};
m_children[1] = new StringLayout(this, string, 1);
m_children[2] = right_expression->createLayout(this);
m_children_layouts[0] = operands[0]->createLayout(this);
for (int i=1; i<number_of_operands; i++) {
m_children_layouts[2*i-1] = new StringLayout(this, string, 1);
m_children_layouts[2*i] = operands[i]->createLayout(this);
}
}
HorizontalLayout::~HorizontalLayout() {
delete m_children[2];
delete m_children[1];
delete m_children[0];
for (int i=0; i<m_number_of_children; i++) {
delete m_children_layouts[i];
}
free(m_children_layouts);
}
void HorizontalLayout::render(KDPoint point) {
// Nothing to render "per se"
}
void HorizontalLayout::render(KDPoint point) { }
KDSize HorizontalLayout::computeSize() {
KDSize size = (KDSize){.width = 0, .height = 0};
@@ -39,23 +41,25 @@ KDSize HorizontalLayout::computeSize() {
}
ExpressionLayout * HorizontalLayout::child(uint16_t index) {
if (index >= 3) {
assert(index <= m_number_of_children);
if (index < m_number_of_children) {
return m_children_layouts[index];
} else {
return nullptr;
}
return m_children[index];
}
KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) {
KDPoint position = (KDPoint){.x = 0, .y = 0};
uint16_t index = 0;
for (int i=0;i<3;i++) {
if (m_children[i] == child) {
for (int i=0;i<m_number_of_children;i++) {
if (m_children_layouts[i] == child) {
index = i;
break;
}
}
if (index > 0) {
ExpressionLayout * previousChild = m_children[index-1];
ExpressionLayout * previousChild = m_children_layouts[index-1];
assert(previousChild != nullptr);
position.x = previousChild->origin().x + previousChild->size().width;
}

View File

@@ -6,7 +6,7 @@
class HorizontalLayout : public ExpressionLayout {
public:
HorizontalLayout(ExpressionLayout * parent, Expression * left_expression, char symbol, Expression * right_expression);
HorizontalLayout(ExpressionLayout * parent, Expression ** operands, int number_of_children, char symbol);
~HorizontalLayout();
protected:
void render(KDPoint point) override;
@@ -14,7 +14,8 @@ class HorizontalLayout : public ExpressionLayout {
ExpressionLayout * child(uint16_t index) override;
KDPoint positionOfChild(ExpressionLayout * child) override;
private:
ExpressionLayout * m_children[3];
int m_number_of_children;
ExpressionLayout ** m_children_layouts;
};
#endif

View File

@@ -17,6 +17,5 @@ Expression::Type Product::type() {
}
ExpressionLayout * Product::createLayout(ExpressionLayout * parent) {
//FIXME: There can be more than two factors now! :-)
return new HorizontalLayout(parent, operand(0), '*', operand(1));
return new HorizontalLayout(parent, m_operands, m_numberOfOperands, '*');
}

15
poincare/src/sine.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include <poincare/sine.h>
#include "layout/horizontal_layout.h"
Expression * Sine::clone() {
return new Sine(m_arg, true);
}
Expression::Type Sine::type() {
return Expression::Type::Sine;
}
float Sine::approximate(Context& context) {
// FIXME: use sine obviously.
return m_arg->approximate(context);
}

View File

@@ -14,5 +14,5 @@ Expression::Type Subtraction::type() {
}
ExpressionLayout * Subtraction::createLayout(ExpressionLayout * parent) {
return new HorizontalLayout(parent, m_operands[0], '-', m_operands[1]);
return new HorizontalLayout(parent, m_operands, 2, '-');
}

15
poincare/src/tangent.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include <poincare/tangent.h>
#include "layout/horizontal_layout.h"
Expression * Tangent::clone() {
return new Tangent(m_arg, true);
}
Expression::Type Tangent::type() {
return Expression::Type::Tangent;
}
float Tangent::approximate(Context& context) {
// FIXME: use tangent obviously.
return m_arg->approximate(context);
}

21
poincare/test/trigo.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include <quiz.h>
#include <poincare.h>
#include <assert.h>
QUIZ_CASE(poincare_parse_trigo) {
{
Expression * e = Expression::parse("sin(0)");
Expression * e2 = e->simplify();
assert(e2->type() == Expression::Type::Sine);
}
{
Expression * e = Expression::parse("cos(0)");
Expression * e2 = e->simplify();
assert(e2->type() == Expression::Type::Cosine);
}
{
Expression * e = Expression::parse("tan(0)");
Expression * e2 = e->simplify();
assert(e2->type() == Expression::Type::Tangent);
}
}

View File

@@ -10,7 +10,6 @@ void print(char * message) {
line_y += line_height;
if (line_y > SCREEN_HEIGHT) {
line_y = 0;
ion_getchar();
// Clear screen maybe?
}
}