Updated Application overview (markdown)
@@ -2,7 +2,7 @@
|
|||||||
[[schemas/architecture.svg]]
|
[[schemas/architecture.svg]]
|
||||||
|
|
||||||
The system is composed of following components (which are technically Gradle subprojects) :
|
The system is composed of following components (which are technically Gradle subprojects) :
|
||||||
* `core` - the SMNP language engine consisting of interpreter (being actually a facade for tokenizer, parser and evaluator), as well as the modules management system
|
* `core` - the SMNP language engine consisting of interpreter (being actually a facade for tokenizer, parser and evaluator), as well as the modules' management system
|
||||||
* `app` - the commandline-based frontend for `core` component
|
* `app` - the commandline-based frontend for `core` component
|
||||||
* modules (`smnp.lang`, `smnp.io`, `smnp.audio.synth` etc.) - a set of external modules that extends the functionality of SMNP scripts
|
* modules (`smnp.lang`, `smnp.io`, `smnp.audio.synth` etc.) - a set of external modules that extends the functionality of SMNP scripts
|
||||||
* `api` - component that provides shared interfaces and abstract classes common for both `core` and each module components.
|
* `api` - component that provides shared interfaces and abstract classes common for both `core` and each module components.
|
||||||
@@ -149,10 +149,10 @@ parenthesesExpr ::= '(' expr ')' ;
|
|||||||
atom ::= parenthesesExpr | identifier | staff | list | map ;
|
atom ::= parenthesesExpr | identifier | staff | list | map ;
|
||||||
```
|
```
|
||||||
|
|
||||||
Therefore `allOf(a, b, c) {...}` is equivalent of `a = a b c`, whereas `oneOf(a, b, c)` is equivalent of `a = a | b | c`.
|
Therefore, `allOf(a, b, c) {...}` is equivalent of `a = a b c`, whereas `oneOf(a, b, c)` is equivalent of `a = a | b | c`.
|
||||||
|
|
||||||
### Parsers' cascade
|
### Parsers' cascade
|
||||||
Parsers are cascadingly composed and thanks to that, they are able to parse a one-dimensional tokens stream to tree structure. For example, the mentioned before `AtomParser` is used by `UnitParser` which is responsible for parsing minus operator and dot operator. In turn, the `UnitParser` is used by `FactorParser` that is responsible for parsing `not` operator and power operator. The `FactorParser` is used by `TermParser` which is responsible for parsing product operator. The `TermParser` is used by `SubexpressionParser` which provides production rules for logic operators, relation operators etc. The `SubexpressionParser` is used by `ExpressionParser` which technically is `oneOf`-based wrapper for `SubexpressionParser` and `LoopParser`. The `ExpressionParser represents all constructions that can product a value and is used by `StatementParser` which is eventually used by `RootParser`.
|
Parsers are cascaded composed and thanks to that, they are able to parse a one-dimensional tokens' stream to tree structure. For example, the mentioned before `AtomParser` is used by `UnitParser` which is responsible for parsing minus operator and dot operator. In turn, the `UnitParser` is used by `FactorParser` that is responsible for parsing `not` operator and power operator. The `FactorParser` is used by `TermParser` which is responsible for parsing product operator. The `TermParser` is used by `SubexpressionParser` which provides production rules for logic operators, relation operators etc. The `SubexpressionParser` is used by `ExpressionParser` which technically is `oneOf`-based wrapper for `SubexpressionParser` and `LoopParser`. The `ExpressionParser represents all constructions that can product a value and is used by `StatementParser` which is eventually used by `RootParser`.
|
||||||
|
|
||||||
The order of each parser in the cascade determines the precedence of each operation and has influence on the
|
The order of each parser in the cascade determines the precedence of each operation and has influence on the
|
||||||
AST's shape. Take look at the following example:
|
AST's shape. Take look at the following example:
|
||||||
@@ -194,8 +194,33 @@ class SubexpressionParser : Parser() {
|
|||||||
return expr4Parser.parse(input)
|
return expr4Parser.parse(input)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
This is a code of `SubexpressionParser` and it consists of 4 subparser cascadingly composed. Because of the `expr4Parser` (responsible for `or` operator) is defined using `expr3Parser` (responsible for `and` operator), the `or` operator has a higher precendee than `and` operator (please compare [[Operators#Operators precedence]].
|
This is a code of `SubexpressionParser` and it consists of 4 subparsers cascaded composed. Because of the `expr4Parser` (responsible for `or` operator) is defined using `expr3Parser` (responsible for `and` operator), the `or` operator has a higher precedence than `and` operator (please compare [[Operators#Operators precedence]]).
|
||||||
Take a look at the following AST:
|
|
||||||
|
Following listening features the composition of `and` and `or` operator nodes honoring their precedence:
|
||||||
```
|
```
|
||||||
$ smnp --ast --dry-run -c "true and false or not false and not false;"
|
$ smnp --ast --dry-run -c "true and false or not false and not false;"
|
||||||
|
RootNode 1:16
|
||||||
|
└─LogicOperatorNode 1:16
|
||||||
|
├─LogicOperatorNode 1:6
|
||||||
|
│ ├─BoolLiteralNode 1:1
|
||||||
|
│ │ └ (bool, »true«, 1:1)
|
||||||
|
│ ├─TokenNode 1:6
|
||||||
|
│ │ └ (and, »and«, 1:6)
|
||||||
|
│ └─BoolLiteralNode 1:10
|
||||||
|
│ └ (bool, »false«, 1:10)
|
||||||
|
├─TokenNode 1:16
|
||||||
|
│ └ (or, »or«, 1:16)
|
||||||
|
└─LogicOperatorNode 1:29
|
||||||
|
├─NotOperatorNode 1:19
|
||||||
|
│ ├─TokenNode 1:19
|
||||||
|
│ │ └ (not, »not«, 1:19)
|
||||||
|
│ └─BoolLiteralNode 1:23
|
||||||
|
│ └ (bool, »false«, 1:23)
|
||||||
|
├─TokenNode 1:29
|
||||||
|
│ └ (and, »and«, 1:29)
|
||||||
|
└─NotOperatorNode 1:33
|
||||||
|
├─TokenNode 1:33
|
||||||
|
│ └ (not, »not«, 1:33)
|
||||||
|
└─BoolLiteralNode 1:37
|
||||||
|
└ (bool, »false«, 1:37)
|
||||||
```
|
```
|
||||||
Reference in New Issue
Block a user