Skip to content

Instantly share code, notes, and snippets.

@loguntsov
Created December 19, 2017 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loguntsov/83b2276b7a855a7648a812e61e1c5a6e to your computer and use it in GitHub Desktop.
Save loguntsov/83b2276b7a855a7648a812e61e1c5a6e to your computer and use it in GitHub Desktop.
/* description: Parses end executes mathematical expressions with strings. */
/* lexical grammar */
%lex
%options case-insensitive
%%
\/\/(.*)\n /* 'COMMENT' */
\/\*(.|\n)*?\*\/ /* 'COMMENT' */
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER';
\"([^"]*)\" %{
//js
yytext = yytext.substr(1,yyleng-2);
return 'STRING';
/*php
$yytext = mb_substr($yytext, 1, mb_strlen($yytext,'utf8') - 2, 'utf8');
return 'STRING';
*/
%}
\'([^']*)\' %{
//js
yytext = yytext.substr(1,yyleng-2);
return 'STRING';
/*php
$yytext = mb_substr($yytext, 1, mb_strlen($yytext,'utf8') - 2, 'utf8');
return 'STRING';
*/
%}
\-\>([^|]*)\| %{
//js
yytext = yytext.substr(2,yyleng-3);
return 'ALL';
/*php
$yytext = mb_substr($yytext, 2, mb_strlen($yytext,'utf8') - 3, 'utf8');
return 'ALL';
*/
%}
'!REPORT' return 'REPORT';
'!ОТЧЕТ' return 'REPORT';
'!INCLUDE' return 'INCLUDE';
'!SHOW' return 'SHOW';
'!ПОКАЗАТЬ' return 'SHOW';
'!CALC' return 'CALC';
'!ВЫЧИСЛИТЬ' return 'CALC';
'!TITLE' return 'TITLE';
'!НАЗВАНИЕ' return 'TITLE';
'!DESCRIPTION' return 'DESCRIPTION';
'!ОПИСАНИЕ' return 'DESCRIPTION';
'!FILTER' return 'FILTER';
'!ИТОГИ' return 'TOTAL';
'!TOTAL' return 'TOTAL';
'!ФИЛЬТРОВАТЬ' return 'FILTER';
'!СКРЫТЬ' return 'HIDE';
'!HIDE' return 'HIDE';
'!ОСЬ' return 'AXIS';
'!ТИП' return 'TYPE';
'!TYPE' return 'TYPE';
'!ЭТО' return 'THIS';
'!THIS' return 'THIS';
'!ПАРАМЕТРЫ' return 'PARAMS';
'!PARAMS' return 'PARAMS';
'!_EXP' return '!_EXP';
'!_SUBSTITUTE_VALUE' return '!_SUBSTITUTE_VALUE';
'(' return '(';
')' return ')';
'.' return '.';
\[\[ return '[[';
\]\] return ']]';
'[' return '[';
']' return ']';
'!BY' return 'BY';
'!ПО' return 'BY';
'!WHERE' return 'WHERE';
'!ГДЕ' return 'WHERE';
'!HAVING' return 'FILTER';
',' return ',';
'=' return '=';
'<=' return '<=';
'>=' return '>=';
'<>' return '<>';
'>' return '>';
'<' return '<';
'+' return '+';
'-' return '-';
'*' return '*';
'/' return '/';
'%' return '%';
':' return ':';
'AND' return 'AND';
\И([ ]|\b) return 'AND';
'OR' return 'OR';
\И\Л\И([ ]|\b) return 'OR';
'NOT' return 'NOT';
\Н\Е([ ]|\b) return 'NOT';
'IN' return 'IN';
\В([ ]|\b) return 'IN';
'ИСТИНА' return 'TRUE';
'ЛОЖЬ' return 'FALSE';
'TRUE' return 'TRUE';
'FALSE' return 'FALSE';
'x-all' %{
/*php
$yytext = \report::ALL;
return 'STRING';
*/ %}
[\w_0-9\%]+\b return 'IDENTIFIER';
<<EOF>> return 'EOF';
. return 'INVALID';
/lex
/* operator associations and precedence */
%right ','
%left '('
%left 'OR',
%left 'AND'
%left 'NOT'
%left '>','<','=<','>=', '<>','='
%left '+' '-'
%left '*' '/'
%right '%'
%nonassoc IDENTIFIER
/*
%left ';'
%left 'PRINT'
%left 'OR',
%left 'AND'
%left 'BETWEEN'
%left 'NOT'
%left '>','<','=<','>=', '<>','='
%left '+' '-'
%left '*' '/'
%left '^'
%right '!'
%left 'SUM', 'ALL', 'RECORD', 'AVG', 'COUNT', 'MAX', 'MIN'
%left construction
%left UMINUS
%nonassoc IDENTIFIER
*/
%start program_main
%% /* language grammar */
program_main
: program EOF
{
/*php
return $this->generator();
*/
}
| '!_EXP' expression EOF
{
/*php
return $2;
*/
}
| '!_SUBSTITUTE_VALUE' subst_value EOF
{
/*php
return $2;
*/
}
;
program
: program operation
| operation
;
operation
: REPORT STRING BY type
{
/*php
$this->makeGenerator($2, $4);
*/
}
| SHOW show_what show_columns
{
/*php
$this->show($2, $3);
*/
}
| SHOW show_columns
{
/*php
$this->show(array('ТАБЛИЦУ'), $2);
*/
}
| WHERE expression
{
/*php
$this->where($2);
*/
}
| WHERE
| CALC calc_columns
| CALC
| FILTER expression
{
/*php
$this->filter($2);
*/
}
| FILTER
| total_section
| PARAMS param_list
{
/*php
$this->params($2);
*/
}
| PARAMS
;
type
: IDENTIFIER
;
column
: IDENTIFIER '.' IDENTIFIER
{
/*php
$$ = $1 . '.' . $3;
*/
}
| IDENTIFIER
;
show_what
: IDENTIFIER
{
/*php
$$ = array($1);
*/
}
| IDENTIFIER 'AND' IDENTIFIER
{
/*php
$$ = array($1, $3);
*/
}
;
total_section
: TOTAL total_list
{
/*php
$this->footer($2);
*/
}
| TOTAL BY IDENTIFIER
{
/*php
$this->group_by($3);
*/
}
| TOTAL BY IDENTIFIER total_list
{
/*php
$this->group_by($3);
$this->footer($4);
*/
}
| TOTAL BY
;
total_list
: total_list ',' total_expression
{
/*php
$$ = $1 + $3;
*/
}
| total_expression
{
/*
$$ = array($1);
*/
}
;
total_expression
: column '=' expression '[' show_options ']'
{
/*php
$$ = array( $1 =>
array(
'footer' => $3
) + $5);
*/
}
| column '=' expression
{
/*php
$$ = array( $1 =>
array(
'footer' => $3
));
*/
}
| column '[' show_options ']'
{
/*php
$$ = array( $1 => $3 );
*/
}
;
show_column
: show_column_name
| show_column_name '[' show_options ']'
{
/*php
$$ = $3 + $1;
*/
}
;
show_column_name
: IDENTIFIER '.' IDENTIFIER
{
/*php
$$ = array(
'type' => static::SHOW_COL_TYPE_ENTITY,
'name' => $1 . '.' . $3,
'entity' => $1,
'col' => $3,
'description' => $1 . '.' . $3,
);
*/
}
| IDENTIFIER
{
/*php
$$ = array(
'type' => static::SHOW_COL_TYPE_CALC,
'calc' => $1,
'name' => $1,
'description' => $1,
);
*/
}
;
show_columns
: show_columns ',' show_column
{
/*php
$$ = array_merge($1, array($3));
*/
}
| show_column
{
/*php
$$ = array($1);
*/
}
| show_columns ','
;
calc_columns
: calc_columns ',' calc_expr
| calc_expr
| calc_columns ','
;
calc_expr
: IDENTIFIER '=' expression '[' show_options ']'
{
/*php
$this->calc($1, $3, $5);
*/
}
| IDENTIFIER '=' expression
{
/*php
$this->calc($1, $3);
*/
}
;
show_options
: show_options show_option
{
/*php
$$ = $1 + $2;
*/
}
| show_option
;
show_option
: TITLE STRING
{
/*php
$$ = array( 'title' => $2 );
*/
}
| DESCRIPTION STRING
{
/*php
$$ = array( 'description' => $2 );
*/
}
| HIDE
{
/*php
$$ = array( 'chart_hide' => true);
*/
}
| AXIS IDENTIFIER
{
/*php
$$ = array( 'chart_axis' => $this->val_replace($2, array(
'СПРАВА' => 'right',
'СЛЕВА' => 'left',
)));
*/
}
| TYPE IDENTIFIER
{
/*php
$$ = array( 'chart_linetype' => $this->val_replace($2, array(
'ЛИНИЯ' => 'line',
'СТОЛБЕЦ' => 'column',
)));
*/
}
| THIS IDENTIFIER
{
/*php
$$ = array('stype' => $this->val_replace($2, array(
'ДЕНЬГИ' => \component::MONEY,
'ПРОЦЕНТ' => \component::PERCENT,
'ЧИСЛО' => \component::NUMBER,
'ЧАС' => \component::HOUR,
'ДАТА' => \component::DATE
)));
*/
}
;
identifier_list
: identifier_list ',' IDENTIFIER
| IDENTIFIER
;
value
: STRING
| NUMBER
| column
;
func
: IDENTIFIER
;
pair
: STRING ALL
{
/*php
$$ = array($1 => trim($2));
*/
}
;
pair_list
: pair_list pair
{
/*php
$$ = $1 + $2;
*/
}
| pair
;
param
: STRING ':' e
{
/*php
$$ = array( $1 => $3 );
*/
}
;
param_list
: param_list param
{
/*php
$$ = $1 + $2;
*/
}
| param
;
column_expression
: func column
| column
;
expression
: e ;
e_list
: e_list ',' e
{
/*php
$$ = array_merge($1, array($3));
*/
}
| e
{
/*php
$$ = array($1);
*/
}
;
e
: IDENTIFIER '(' e_list ')'
{
/*php
$$ = static::func_generate($1, $3);
*/
}
| '(' e ')'
{
/*php
$$ = $2;
*/
}
| e '=' e
{
/*php
$$ = \uniExpressionWhereGlobal::create(function(array $values) {
if (\uniExpressionWhereGlobal::isAll($values['#1']) OR
\uniExpressionWhereGlobal::isAll($values['#2']))
{
return 'true';
} else {
return '#1 = #2';
}
}
,array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
$a = $exp->get('#1')->generate($context);
$b = $exp->get('#2')->generate($context);
if ($a === \report::ALL OR $b===\report::ALL) return TRUE;
return $a == $b;
});
*/
}
| e '<>' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 <> #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) != $exp->get('#2')->generate($context);
});
*/
}
| e '>' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 > #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) > $exp->get('#2')->generate($context);
});
*/
}
| e '<' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 < #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) < $exp->get('#2')->generate($context);
});
*/
}
| e '<=' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 <= #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) <= $exp->get('#2')->generate($context);
});
*/
}
| e '>=' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 >= #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) >= $exp->get('#2')->generate($context);
});
*/
}
| e '+' e
{
/*php
$$ = static::plus($1, $3);
*/
}
| e '-' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 - #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) - $exp->get('#2')->generate($context);
});
*/
}
| e '*' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 * #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) * $exp->get('#2')->generate($context);
});
*/
}
| e '/' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 / #2', array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return \math::div($exp->get('#1')->generate($context), $exp->get('#2')->generate($context));
});
*/
}
| e 'AND' e
{
/*php
$$ = \uniExpressionWhereGlobal::create(function(array $values) {
$a = \uniExpressionWhereGlobal::isTrue($values['#1']);
$b = \uniExpressionWhereGlobal::isTrue($values['#2']);
if ($a AND $b) return 'true';
if ($a) return '#2';
if ($b) return '#1';
return '#1 AND #2';
}
, array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return (($exp->get('#1')->generate($context)) !== false) AND (($exp->get('#2')->generate($context) !== false));
});
*/
}
| e 'OR' e
{
/*php
$$ = \uniExpressionWhereGlobal::create(function(array $values) {
$a = \uniExpressionWhereGlobal::isTrue($values['#1']);
$b = \uniExpressionWhereGlobal::isTrue($values['#2']);
if ($a OR $b) return 'true';
if ($a) return '#2';
if ($b) return '#1';
return '#1 OR #2';
}, array(
'#1' => $1,
'#2' => $3,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return (($exp->get('#1')->generate($context)) !== false) OR (($exp->get('#2')->generate($context) !== false));
});
*/
}
| 'NOT' e
{
/*php
$$ = \uniExpressionWhereGlobal::create('NOT #1', array(
'#1' => $2,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return ($exp->get('#1')->generate($context) === false);
});
*/
}
| e 'IN' '[' e_list ']'
{
/*php
// TODO: ДОДЕЛАТЬ !!!
$$ = \uniExpressionWhereGlobal::create('#1 IN #2 ', array(
'#1' => $1,
'#2' => implode(',', array_map(function($expr) {
return $expr->generate($context);
}, $4)),
'#3' => $4,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return ($exp->get('#1')->generate($context) === false);
});
*/
}
| column
{
/*php
$$ = \uniExpressionWhereColumn::create($1);
*/
}
| IDENTIFIER
{
/*php
$$ = \uniExpressionWhereColumn::create($1);
*/
}
| NUMBER
{
/*php
$$ = \uniExpressionConst::create($1, \uniExpressionConst::TYPE_NUMBER);
*/
}
| STRING
{
/*php
$$ = \uniExpressionConst::create($1);
*/
}
| subst_value
{
/*php
$this->addSubsValue($1);
*/
}
| TRUE
{
/*php
$$ = \uniExpressionConst::create(true);
*/
}
| FALSE
{
/*php
$$ = \uniExpressionConst::create(false);
*/
}
| e '%'
{
/*php
$$ = \uniExpressionWhereGlobal::create('#1 / 100', array(
'#1' => $1,
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
return $exp->get('#1')->generate($context) / 100;
});
*/
}
| '[' e_list ']'
{
/*php
$$ = \uniExpressionWhereGlobal::create('', array(
'#1' => $2
), function(\uniExpressionWhereGlobal $exp, \uniContextValue $context) {
$ret = array();
foreach($exp->get('#1') as $e) {
$ret[] = $e->generate($context);
}
return $ret;
});
*/
}
| '[' ']'
{
/*php
$$ = \uniExpressionConst::create(array());
*/
}
;
subst_value
: '[[' IDENTIFIER STRING pair_list ']]'
{
/*php
$$ = $this->createSubstValue(array(
'type' => $2,
'caption' => $3,
'list' => $4,
));
*/
}
| '[[' IDENTIFIER pair_list ']]'
{
/*php
$$ = $this->createSubstValue(array(
'type' => $2,
'list' => $3,
));
*/
}
| '[[' IDENTIFIER STRING ']]'
{
/*php
$$ = $this->createSubstValue(array(
'type' => $2,
'caption' => $3,
));
*/
}
| '[[' IDENTIFIER ']]'
{
/*php
$$ = $this->createSubstValue(array(
'type' => $2,
));
*/
}
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment