diff --git a/app/Makefile b/app/Makefile index fba1326d1..d662c1a4d 100644 --- a/app/Makefile +++ b/app/Makefile @@ -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) diff --git a/app/app.cpp b/app/app.cpp index 043984995..eede4f5e7 100644 --- a/app/app.cpp +++ b/app/app.cpp @@ -6,7 +6,7 @@ extern "C" { #include -#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(); diff --git a/app/text_input.cpp b/app/utils.cpp similarity index 92% rename from app/text_input.cpp rename to app/utils.cpp index 522203310..f0e1c16d4 100644 --- a/app/text_input.cpp +++ b/app/utils.cpp @@ -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; diff --git a/app/text_input.h b/app/utils.h similarity index 61% rename from app/text_input.h rename to app/utils.h index b7490c2ff..ca78fcae1 100644 --- a/app/text_input.h +++ b/app/utils.h @@ -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 diff --git a/poincare/Makefile b/poincare/Makefile index 1408138a6..c7144dd49 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -4,23 +4,28 @@ objs += $(addprefix poincare/src/,\ binary_operation.o\ commutative_operation.o\ context.o\ + cosinus.o\ expression.o\ expression_lexer.o\ expression_parser.o\ float.o\ fraction.o\ + function.o\ integer.o\ leaf_expression.o\ power.o\ product.o\ + sinus.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/,\ diff --git a/poincare/include/poincare.h b/poincare/include/poincare.h index eeaf014ef..4b89926c0 100644 --- a/poincare/include/poincare.h +++ b/poincare/include/poincare.h @@ -3,13 +3,17 @@ #include #include +#include #include -#include #include +#include +#include #include #include #include +#include #include #include +#include #endif diff --git a/poincare/include/poincare/cosinus.h b/poincare/include/poincare/cosinus.h new file mode 100644 index 000000000..f23e66e4c --- /dev/null +++ b/poincare/include/poincare/cosinus.h @@ -0,0 +1,14 @@ +#ifndef POINCARE_COSINUS_H +#define POINCARE_COSINUS_H + +#include + +class Cosinus : public Function { + public: + Cosinus(Expression * arg, bool clone_arg=true): Function(arg, (char*) "cos", clone_arg) {} + float approximate(Context& context) override; + Type type() override; + Expression * clone() override; +}; + +#endif diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 3fe1bbf8f..44dcd345f 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -10,13 +10,16 @@ class Expression { public: enum class Type : uint8_t { Addition, + Cosinus, Float, Fraction, Integer, Power, Product, + Sinus, Subtraction, - Symbol + Symbol, + Tangent, }; static Expression * parse(char const * string); virtual ~Expression(); diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h new file mode 100644 index 000000000..e02e7e388 --- /dev/null +++ b/poincare/include/poincare/function.h @@ -0,0 +1,19 @@ +#ifndef POINCARE_FUNCTION_H +#define POINCARE_FUNCTION_H + +#include + +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 diff --git a/poincare/include/poincare/sinus.h b/poincare/include/poincare/sinus.h new file mode 100644 index 000000000..a970aac09 --- /dev/null +++ b/poincare/include/poincare/sinus.h @@ -0,0 +1,14 @@ +#ifndef POINCARE_SINUS_H +#define POINCARE_SINUS_H + +#include + +class Sinus : public Function { + public: + Sinus(Expression * arg, bool clone_arg=true): Function(arg, (char*) "sin", clone_arg) {} + float approximate(Context& context) override; + Type type() override; + Expression * clone() override; +}; + +#endif diff --git a/poincare/include/poincare/tangent.h b/poincare/include/poincare/tangent.h new file mode 100644 index 000000000..06ffbae06 --- /dev/null +++ b/poincare/include/poincare/tangent.h @@ -0,0 +1,14 @@ +#ifndef POINCARE_TANGENT_H +#define POINCARE_TANGENT_H + +#include + +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 diff --git a/poincare/src/cosinus.cpp b/poincare/src/cosinus.cpp new file mode 100644 index 000000000..070b82a2a --- /dev/null +++ b/poincare/src/cosinus.cpp @@ -0,0 +1,15 @@ +#include +#include "layout/horizontal_layout.h" + +Expression * Cosinus::clone() { + return new Cosinus(m_arg, true); +} + +Expression::Type Cosinus::type() { + return Expression::Type::Cosinus; +} + +float Cosinus::approximate(Context& context) { + // FIXME: use cosinus obviously. + return m_arg->approximate(context); +} diff --git a/poincare/src/expression_lexer.l b/poincare/src/expression_lexer.l index 5dd2bb7b4..008e5fca5 100644 --- a/poincare/src/expression_lexer.l +++ b/poincare/src/expression_lexer.l @@ -43,6 +43,9 @@ class Expression; [0-9]+ { yylval->string = yytext; return(INTEGER); } [A-Za-z]+ { yylval->string = yytext; return(SYMBOL); } +sin {return(SINUS);} +cos {return(COSINUS);} +tan {return(TANGENT);} \+ { return(PLUS); } \- { return(MINUS); } \* { return(MULTIPLY); } diff --git a/poincare/src/expression_parser.y b/poincare/src/expression_parser.y index 505f1505b..bb3dd2b14 100644 --- a/poincare/src/expression_parser.y +++ b/poincare/src/expression_parser.y @@ -54,6 +54,9 @@ void poincare_expression_yyerror(void * scanner, Expression ** expressionOutput, %token MULTIPLY %token DIVIDE %token POW +%token SINUS +%token COSINUS +%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; } + | SINUS LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Sinus($3); } + | COSINUS LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Cosinus($3); } + | TANGENT LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = new Tangent($3); } ; %% diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp new file mode 100644 index 000000000..e0ac86286 --- /dev/null +++ b/poincare/src/function.cpp @@ -0,0 +1,35 @@ +extern "C" { +#include +} +#include +#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; +} diff --git a/poincare/src/layout/function_layout.cpp b/poincare/src/layout/function_layout.cpp new file mode 100644 index 000000000..02bc5410b --- /dev/null +++ b/poincare/src/layout/function_layout.cpp @@ -0,0 +1,73 @@ +extern "C" { +#include +#include +} +#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; +} + diff --git a/poincare/src/layout/function_layout.h b/poincare/src/layout/function_layout.h new file mode 100644 index 000000000..0b689dfcf --- /dev/null +++ b/poincare/src/layout/function_layout.h @@ -0,0 +1,21 @@ +#ifndef POINCARE_FUNCTION_LAYOUT_H +#define POINCARE_FUNCTION_LAYOUT_H + +#include +#include + +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 + diff --git a/poincare/src/layout/horizontal_layout.cpp b/poincare/src/layout/horizontal_layout.cpp index e1297a0d2..0ba763f4b 100644 --- a/poincare/src/layout/horizontal_layout.cpp +++ b/poincare/src/layout/horizontal_layout.cpp @@ -5,25 +5,28 @@ extern "C" { #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, int number_of_operands, Expression ** operands, char symbol) { + m_number_of_operands = number_of_operands; + // FIXME: This implementation is not optimal as the operator layout is created and stored a lot of times. + // The reason for this is how the layouts are drawn. + m_children_layouts = (ExpressionLayout **)malloc((2*m_number_of_operands-)*sizeof(ExpressionLayout *)); + m_operator_layout = new StringLayout(this, string, 1); char string[2] = {symbol, '\0'}; - m_children[1] = new StringLayout(this, string, 1); - - m_children[2] = right_expression->createLayout(this); + for (int i=1; icreateLayout(); + } } HorizontalLayout::~HorizontalLayout() { - delete m_children[2]; - delete m_children[1]; - delete m_children[0]; + for (int i(0); i= 3) { + if (index >= 2*m_number_of_operands) { return nullptr; } - return m_children[index]; + return m_children_layouts[index]; } KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) { diff --git a/poincare/src/layout/horizontal_layout.h b/poincare/src/layout/horizontal_layout.h index d4cb6a04a..4482aca87 100644 --- a/poincare/src/layout/horizontal_layout.h +++ b/poincare/src/layout/horizontal_layout.h @@ -6,7 +6,7 @@ class HorizontalLayout : public ExpressionLayout { public: - HorizontalLayout(ExpressionLayout * parent, Expression * left_expression, char symbol, Expression * right_expression); + HorizontalLayout(ExpressionLayout * parent, int number_of_operands, Expression ** operands, char symbol); ~HorizontalLayout(); protected: void render(KDPoint point) override; @@ -14,7 +14,9 @@ class HorizontalLayout : public ExpressionLayout { ExpressionLayout * child(uint16_t index) override; KDPoint positionOfChild(ExpressionLayout * child) override; private: - ExpressionLayout * m_children[3]; + int m_number_of_operands; + ExpressionLayout ** m_children_layouts; + ExpressionLayout * m_operator_layout; }; #endif diff --git a/poincare/src/sinus.cpp b/poincare/src/sinus.cpp new file mode 100644 index 000000000..9a73559a3 --- /dev/null +++ b/poincare/src/sinus.cpp @@ -0,0 +1,15 @@ +#include +#include "layout/horizontal_layout.h" + +Expression * Sinus::clone() { + return new Sinus(m_arg, true); +} + +Expression::Type Sinus::type() { + return Expression::Type::Sinus; +} + +float Sinus::approximate(Context& context) { + // FIXME: use sinus obviously. + return m_arg->approximate(context); +} diff --git a/poincare/src/tangent.cpp b/poincare/src/tangent.cpp new file mode 100644 index 000000000..6eb92af4c --- /dev/null +++ b/poincare/src/tangent.cpp @@ -0,0 +1,15 @@ +#include +#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); +} diff --git a/quiz/src/runner.c b/quiz/src/runner.c index a19e202d8..bb76367cb 100644 --- a/quiz/src/runner.c +++ b/quiz/src/runner.c @@ -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? } }