expression_lexer.l 9.01 KB
/* Normally, Flex will call yywrap when reaching an end-of-file. We don't want
 * to deal with files anyway, so let's just disable this. */
%option noyywrap

/* WARNING:
 * If you think about using the bison-bridge option, note that this assumes
 * that the bison parser is reentrant (pure-parser option).
 *
 * Note also that bison and flex (when not reentrant) communicate with each
 * other by using global variables such as yylval or yylineno, these variables
 * will also be prefixed (here we have poicare_expression_yylval).
 *
 * When using a reentrant parser, these variables become pointers and are
 * not prefixed (this is probably a bug in bison, or at least is a bug in my
 * opinion).
 *
 * Using reentrant parsers and lexer is not useful for us as we neither use
 * multiple inputs, different threads calling the lexer-parser nor do we read
 * nested files.
 */

/* Normally, on each new input file the scanner calls isatty() in an attempt to
 * determine whether the scanner's input source is interactive and thus should
 * be read a character at a time.
 * We obviously do *not* provide isatty(), and we know we're never going to use
 * an interactive input source. */
%option never-interactive

%{
/* Flex generate a lexer, a function that outputs tokens.
 * Those tokens (and the optional value that they can be attached) are defined
 * in the Bison grammar. To use those token definitions, we need to include the
 * header generated by Bison.
 * Also, since some tokens can have an "Expression *" value attached, we'll
 * need "Expression" to be defined before including that header.
 * We could use the '%code requires{}' directive to make sure that Expression is
 * well defined in the parser header, but this directive only comes in bison 3,
 * which is not installed by default on MacOS, we thus made the choice to prefer
 * compatibility with MacOS's default version (2.3) instead of using the code
 * requires feature. */
#include <cmath>
#include <poincare.h>
#include "expression_parser.hpp"
using namespace Poincare;

/* Flex has provision for reading files. We'll never use this, so we're defining
 * YY_INPUT which effectively disables taking input from a file. */
#define YY_INPUT

/* Flex can print to stdout what token it matches by calling the ECHO function.
 * We don't want that feature : we don't even have printf ! */
#define ECHO

/* This defines the size of the flex buffer size.
 * By default this buffer is of 16k, but we don't have the luxury to use so much
 * memory on a microcontroller.
 * The choice of 256 Bytes is the size of the input buffer given to flex in the
 * current implementation (the app takes a maximum of 256).
 */
#undef YY_BUF_SIZE
#define YY_BUF_SIZE 256

#define fprintf(...) ((void)0)
#define exit(...) abort()

%}

%%

 /* If two patterns can match the same input, flex resolves the ambiguity:
  * - By matching the longest possible string
  * - In a tie, by using the pattern that appears first
  *
  * Also note that yytext is guaranteed to be null-terminated when the token is
  * being built, (i.e. when flex calls our code snippet), but this is achieved
  * by flex temporarily swapping the last character. Afterwards the pointer is
  * still valid but the string isn't null-terminated anymore.
  */
  /* We designed our own extended-ASCII to include requiered symbols in less
   * than 255 glyphs. The file ion/include/ion/charset.h lists all added
   * non-ASCII symbols with their char associated. For example, the char \x89
   * refered to Pi symbols. This artefact leads to the following lexer rules
   * starting with \x. */

[0-9]+ { poincare_expression_yylval.string.address = yytext; poincare_expression_yylval.string.length = yyleng; return DIGITS; }
[A-Zxn] { poincare_expression_yylval.character = yytext[0]; return SYMBOL; }
M[0-9] { poincare_expression_yylval.character = Symbol::matrixSymbol(yytext[1]); return SYMBOL; }
u\(n\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::un; return SYMBOL; }
u\(n\+1\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::un1; return SYMBOL; }
v\(n\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::vn; return SYMBOL; }
v\(n\+1\) { poincare_expression_yylval.character = Symbol::SpecialSymbols::vn1; return SYMBOL; }
acos { poincare_expression_yylval.expression = new ArcCosine(); return FUNCTION; }
acosh { poincare_expression_yylval.expression = new HyperbolicArcCosine(); return FUNCTION; }
abs { poincare_expression_yylval.expression = new AbsoluteValue(); return FUNCTION; }
ans { poincare_expression_yylval.character = Symbol::SpecialSymbols::Ans; return SYMBOL; }
arg { poincare_expression_yylval.expression = new ComplexArgument(); return FUNCTION; }
asin { poincare_expression_yylval.expression = new ArcSine(); return FUNCTION; }
asinh { poincare_expression_yylval.expression = new HyperbolicArcSine(); return FUNCTION; }
atan { poincare_expression_yylval.expression = new ArcTangent(); return FUNCTION; }
atanh { poincare_expression_yylval.expression = new HyperbolicArcTangent(); return FUNCTION; }
binomial { poincare_expression_yylval.expression = new BinomialCoefficient(); return FUNCTION; }
ceil { poincare_expression_yylval.expression = new Ceiling(); return FUNCTION; }
confidence { poincare_expression_yylval.expression = new ConfidenceInterval(); return FUNCTION; }
diff { poincare_expression_yylval.expression = new Derivative(); return FUNCTION; }
dim { poincare_expression_yylval.expression = new MatrixDimension(); return FUNCTION; }
det { poincare_expression_yylval.expression = new Determinant(); return FUNCTION; }
conj { poincare_expression_yylval.expression = new Conjugate(); return FUNCTION; }
cos { poincare_expression_yylval.expression = new Cosine(); return FUNCTION; }
cosh { poincare_expression_yylval.expression = new HyperbolicCosine(); return FUNCTION; }
factor { poincare_expression_yylval.expression = new Factor(); return FUNCTION; }
floor { poincare_expression_yylval.expression = new Floor(); return FUNCTION; }
frac { poincare_expression_yylval.expression = new FracPart(); return FUNCTION; }
gcd { poincare_expression_yylval.expression = new GreatCommonDivisor(); return FUNCTION; }
im { poincare_expression_yylval.expression = new ImaginaryPart(); return FUNCTION; }
int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; }
inverse { poincare_expression_yylval.expression = new MatrixInverse(); return FUNCTION; }
lcm { poincare_expression_yylval.expression = new LeastCommonMultiple(); return FUNCTION; }
ln { poincare_expression_yylval.expression = new NaperianLogarithm(); return FUNCTION; }
log { poincare_expression_yylval.expression = new Logarithm(); return FUNCTION; }
permute { poincare_expression_yylval.expression = new PermuteCoefficient(); return FUNCTION; }
prediction95 { poincare_expression_yylval.expression = new PredictionInterval(); return FUNCTION; }
prediction { poincare_expression_yylval.expression = new ConfidenceInterval(); return FUNCTION; }
product { poincare_expression_yylval.expression = new Product(); return FUNCTION; }
quo { poincare_expression_yylval.expression = new DivisionQuotient(); return FUNCTION; }
random { poincare_expression_yylval.expression = new Random(); return FUNCTION; }
randint { poincare_expression_yylval.expression = new Randint(); return FUNCTION; }
re { poincare_expression_yylval.expression = new RealPart(); return FUNCTION; }
rem { poincare_expression_yylval.expression = new DivisionRemainder(); return FUNCTION; }
root { poincare_expression_yylval.expression = new NthRoot(); return FUNCTION; }
round { poincare_expression_yylval.expression = new Round(); return FUNCTION; }
sin { poincare_expression_yylval.expression = new Sine(); return FUNCTION; }
sinh { poincare_expression_yylval.expression = new HyperbolicSine(); return FUNCTION; }
sum { poincare_expression_yylval.expression = new Sum(); return FUNCTION; }
tan { poincare_expression_yylval.expression = new Tangent(); return FUNCTION; }
tanh { poincare_expression_yylval.expression = new HyperbolicTangent(); return FUNCTION; }
trace { poincare_expression_yylval.expression = new MatrixTrace(); return FUNCTION; }
transpose { poincare_expression_yylval.expression = new MatrixTranspose(); return FUNCTION; }
undef { poincare_expression_yylval.expression = new Undefined(); return UNDEFINED; }
inf { poincare_expression_yylval.expression = new Undefined(); return UNDEFINED; }
\x89 { poincare_expression_yylval.character = yytext[0]; return SYMBOL; }
\x8c { return EE; }
\x90 { poincare_expression_yylval.expression = new SquareRoot(); return FUNCTION; }
\x8b { poincare_expression_yylval.character = yytext[0]; return SYMBOL; }
\x8e { poincare_expression_yylval.character = yytext[0]; return SYMBOL; }
\x8f { return STO; }
\+ { return PLUS; }
\- { return MINUS; }
\x93 { return MULTIPLY; }
\* { return MULTIPLY; }
\/ { return DIVIDE; }
\^ { return POW; }
\! { return BANG; }
\( { return LEFT_PARENTHESIS; }
\) { return RIGHT_PARENTHESIS; }
\{ { return LEFT_BRACE; }
\} { return RIGHT_BRACE; }
\[ { return LEFT_BRACKET; }
\] { return RIGHT_BRACKET; }
\, { return COMMA; }
\. { return DOT; }
[ ]+ /* Ignore whitespaces */
. { return UNDEFINED_SYMBOL; }

%%