2020-06-04 11:04:03 +00:00
|
|
|
/*
|
|
|
|
This file is part of libeval, a simple math expression evaluator
|
|
|
|
|
|
|
|
Copyright (C) 2017 Michael Geselbracht, mgeselbracht3@gmail.com
|
2020-07-03 16:36:33 +00:00
|
|
|
Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
2020-06-04 11:04:03 +00:00
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2020-08-10 12:47:01 +00:00
|
|
|
%token_type { LIBEVAL::T_TOKEN }
|
2020-06-04 11:04:03 +00:00
|
|
|
%extra_argument { LIBEVAL::COMPILER* pEval }
|
|
|
|
|
2020-08-10 12:47:01 +00:00
|
|
|
%type nt {LIBEVAL::TREE_NODE*}
|
|
|
|
|
2020-06-04 11:04:03 +00:00
|
|
|
%nonassoc G_IDENTIFIER G_ASSIGN G_SEMCOL.
|
2020-06-16 19:48:47 +00:00
|
|
|
%left G_BOOL_AND.
|
|
|
|
%left G_BOOL_OR.
|
|
|
|
%left G_BOOL_XOR.
|
|
|
|
%nonassoc G_LESS_THAN G_GREATER_THAN G_LESS_EQUAL_THAN G_GREATER_EQUAL_THAN G_EQUAL G_NOT_EQUAL.
|
|
|
|
%right G_BOOL_NOT.
|
2020-06-04 11:04:03 +00:00
|
|
|
%left G_PLUS G_MINUS.
|
|
|
|
%left G_DIVIDE G_MULT.
|
|
|
|
%nonassoc G_STRUCT_REF.
|
2020-06-16 19:48:47 +00:00
|
|
|
%nonassoc G_UNIT.
|
2020-06-04 11:04:03 +00:00
|
|
|
|
|
|
|
%include {
|
|
|
|
#include <assert.h>
|
2020-06-13 23:19:22 +00:00
|
|
|
#include <libeval_compiler/libeval_compiler.h>
|
2020-06-04 11:04:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
%syntax_error {
|
|
|
|
pEval->parseError("Syntax error");
|
|
|
|
}
|
|
|
|
|
|
|
|
%parse_accept {
|
|
|
|
pEval->parseOk();
|
|
|
|
}
|
|
|
|
|
|
|
|
main ::= in.
|
|
|
|
|
|
|
|
/* Allow multiple statements in input string: x=1; y=2 */
|
|
|
|
in ::= stmt.
|
|
|
|
in ::= in stmt.
|
|
|
|
|
|
|
|
/* A statement can be empty, an expr or an expr followed by ';' */
|
|
|
|
stmt ::= G_ENDS.
|
2020-08-10 12:47:01 +00:00
|
|
|
stmt ::= nt(A) G_ENDS. { pEval->setRoot(A); }
|
|
|
|
|
|
|
|
nt(A) ::= G_VALUE(B).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_NUMBER, B.value );
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= G_VALUE(B) G_UNIT(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_NUMBER, B.value );
|
|
|
|
A->leaf[0] = newNode( pEval, TR_UNIT, C.value );
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= G_STRING(B).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_STRING, B.value );
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= G_IDENTIFIER(B).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_IDENTIFIER, B.value );
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_LESS_THAN nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_LESS );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_GREATER_THAN nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_GREATER );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_LESS_EQUAL_THAN nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_LESS_EQUAL );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_GREATER_EQUAL_THAN nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_GREATER_EQUAL );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_NOT_EQUAL nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_NOT_EQUAL );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_BOOL_AND nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_BOOL_AND );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_BOOL_OR nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_BOOL_OR );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_PLUS nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_ADD );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
2020-08-10 14:54:45 +00:00
|
|
|
nt(A) ::= G_PLUS nt(B).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, B->op, B->value );
|
|
|
|
A->leaf[0] = B->leaf[0];
|
|
|
|
A->leaf[1] = B->leaf[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nt(A) ::= G_MINUS nt(B).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_SUB );
|
|
|
|
A->leaf[0] = newNode( pEval, TR_NUMBER );
|
|
|
|
A->leaf[1] = B;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-10 12:47:01 +00:00
|
|
|
nt(A) ::= nt(B) G_MINUS nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_SUB );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_MULT nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_MUL );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_DIVIDE nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_DIV );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_EQUAL nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_EQUAL );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= nt(B) G_STRUCT_REF nt(C).
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_STRUCT_REF );
|
|
|
|
A->leaf[0] = B;
|
|
|
|
A->leaf[1] = C;
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= G_PARENL nt(B) G_PARENR.
|
|
|
|
{
|
2020-08-10 14:19:18 +00:00
|
|
|
A = newNode( pEval, B->op, B->value );
|
2020-08-10 12:47:01 +00:00
|
|
|
A->leaf[0] = B->leaf[0];
|
|
|
|
A->leaf[1] = B->leaf[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
nt(A) ::= G_IDENTIFIER(F) G_PARENL nt(B) G_PARENR.
|
|
|
|
{
|
|
|
|
A = newNode( pEval, TR_OP_FUNC_CALL );
|
|
|
|
A->leaf[0] = newNode( pEval, TR_IDENTIFIER, F.value);
|
|
|
|
A->leaf[1] = B;
|
|
|
|
}
|