DMNTK | Decision Model and Notation Toolkit
FEEL grammar and parsing tables generator:
FEEL
language in the format acceptable by Bison
parser generator.Rust
language.Excerpt from Decision Model and Notation™ specification, ver. 1.3, pp. 105-179:
"DMN 1.3 defines the friendly enough expression language (FEEL) for the purpose of giving standard executable semantics to many kinds of expressions in decision model. [...] FEEL syntax is defined as a grammar here [...]".
dmntk-feel-grammar crate defines the Bison
version of the full FEEL
grammar
as defined in clause 10.3 of cited above Decision Model and Notation™ specification.
In addition, dmntk-feel-grammar crate provides functionality for generating LALR parsing tables
and reduce actions
, ready to be used by LALR
parser written in Rust.
Such parser that uses the output from dmntk-feel-grammar crate
is implemented in dmntk-feel-parser.
Inputs and outputs of dmntk-feel-grammar crate are depicted in the following diagram:
dmntk-feel-grammar takes Yacc/Bison
compatible grammar file as an input.
Grammar file for FEEL
language is defined as a source file named feel.y
and compiled
with this crate.
The output from dmntk-feel-grammar create is a file named lalr.rs
.
This file is a Rust source code that contains definitions of parsing tables and reduce actions.
dmntk-feel-grammar crate uses Bison parser generator
to process the input grammar file and to generate the parser source for C
language.
Command that generates the parser for C
language using Bison
may look like this:
shell
$ LANG=C bison -l -r states -L C feel.y
Bison
generates C
source file that contains the generated parsing tables.
dmntk-feel-grammar extracts those tables, adds reduce action definitions and saves
the result code in lalr.rs
file as Rust source code.
dmntk-feel-grammar requires:
- installed the newest Rust nightly version,
- installed the newest Bison
version.
dmntk-feel-grammar may be used as a library.
Add dmntk-feel-grammar
to your Cargo.toml
:
toml
[dependencies]
dmntk-feel-grammar = "0.0.20"
To generate LALR parsing tables, call lalr_rust_tables
function:
```rust use dmntkfeelgrammar::lalrrusttables;
fn main() { lalrrusttables("./src/lalr.rs"); } ```
The following grammar rules are taken from Decision Model and Notation™ ver. 1.3
expression =
textual_expression =
(
, expression , )
;textualexpressions = textual expression , { ,
, textualexpression } ;
arithmetic_expression =
simpleexpression = arithmeticexpression | simple_value ;
simpleexpressions = simpleexpression , { ,
, simple_expression } ;
simplepositiveunary_test =
<
| <=
| >
| >=
] , endpoint |interval = ( openintervalstart | closedintervalstart ) ,
endpoint , ..
, endpoint ,
( openintervalend | closedintervalend ) ;
openintervalstart = (
| ]
;
closedintervalstart = [
;
openintervalend = )
| [
;
closedintervalend = ]
;
positiveunarytest = expression ;
positiveunarytests = positiveunarytest , { ,
, positiveunarytest } ;
unary_tests =
not
, (
, positiveunarytests, )
|-
;endpoint = simple_value ;
simplevalue = qualifiedname | simple_literal ;
qualified_name = name , { .
, name } ;
addition = expression , +
, expression ;
subtraction = expression , -
, expression ;
multiplication = expression , *
, expression ;
division = expression , /
, expression ;
exponentiation = expression, **
, expression ;
arithmetic_negation = -
, expression ;
name = namestart , { namepart | additionalnamesymbols } ;
namestart = namestartchar, { namepart_char } ;
namepart = namepartchar , { namepart_char } ;
namestartchar = ?
| [A-Z]
| _
| [a-z]
| [\uC0-\uD6]
| [\uD8-\uF6]
| [\uF8-\u2FF]
| [\u370-\u37D]
| [\u37F-\u1FFF]
| [\u200C-\u200D]
| [\u2070-\u218F]
| [\u2C00-\u2FEF]
| [\u3001-\uD7FF]
| [\uF900-\uFDCF]
| [\uFDF0-\uFFFD]
| [\u10000-\uEFFFF]
;
namepartchar = namestartchar | digit | \uB7
| [\u0300-\u036F]
| [\u203F-\u2040]
;
additionalnamesymbols = .
| /
| -
| ’
| +
| *
;
literal = simple_literal | null
;
simpleliteral = numericliteral | stringliteral | booleanliteral | datetimeliteral ;
stringliteral = "
, { character – ("
| verticalspace) | stringescapesequence}, "
;
boolean_literal = true
| false
;
numeric_literal = [ -
] , ( digits , [ .
, digits ] | .
, digits ) ;
digit = [0-9] ;
digits = digit , { digit } ;
function_invocation = expression , parameters ;
parameters = (
, ( namedparameters | positionalparameters ) , )
;
namedparameters = parametername , :
, expression , { ,
, parameter name , :
, expression } ;
parameter_name = name ;
positional_parameters = [ expression , { ,
, expression } ] ;
path_expression = expression , .
, name ;
for_expression = for
, name , in
, iteration context { ,
, name , in
, iteration context } , return
, expression ;
if_expression = if
, expression , then
, expression , else
expression ;
quantified_expression = (some
| every
) , name , in
, expression , { ,
, name , in
, expression } , satisfies
, expression ;
disjunction = expression , or
, expression ;
conjunction = expression , and
, expression ;
comparison =
=
| !=
| <
| <=
| >
| >=
) , expression |between
, expression , and
, expression |in
, positiveunarytest |in
, (
, positive unary tests, )
;filter_expression = expression , [
, expression , ]
;
instance_of = expression , instance
, of
, type ;
type =
list
<
type >
|context
<
name :
type { ,
name :
type } >
|function
<
[ type { ,
type } ] >
->
type ;boxedexpression = list | functiondefinition | context ;
list = [
, [ expression , { ,
, expression } ] , ]
;
functiondefinition = function
, (
, [ formalparameter { ,
, formal parameter } ] , )
, [ external
] , expression ;
formalparameter = parametername [:
type ] ;
context = {
, [contextentry , { ,
, contextentry } ] , }
;
context_entry = key , :
, expression ;
key = name | string_literal ;
datetimeliteral = atliteral | functioninvocation ;
whitespace = verticalspace | \u0009
| \u0020
| \u0085
| \u00A0
| \u1680
| \u180E
| [\u2000-\u200B]
| \u2028
| \u2029
| \u202F
| \u205F
| \u3000
| \uFEFF
;
vertical_space = [\u000A-\u000D]
;
iteration_context = expression, [ ..
, expression ] ;
stringescapesequence = \'
| \"
| \\
| \n
| \r
| \t
| code_point;
atliteral = @
, stringliteral
dmntk-feel-grammar is distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE-MIT and LICENSE-APACHE for details.