Created
December 19, 2017 17:47
-
-
Save loguntsov/e258a6112e966f98a7329f0325732a66 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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