Updated Application overview (markdown)

Bartłomiej Przemysław Pluta
2020-03-30 18:03:39 +02:00
parent c3307c016c
commit 980880f7d1

@@ -141,10 +141,61 @@ class AtomParser : Parser() {
}
}
```
In this example you can notice both `allOf()` and `oneOf()` helper methods. The first one returns success (and parsed node) if and only if all of its subparsers returns success as well. In contrast to that, the `oneOf()` method returns success with parsed node when any of its subparsers returns success. The `oneOf()` method seeks for the first parser that returns success. When it finds it, it immediately returns success with node returned from its subparser and does not execute further subparsers. Because the `oneOf()` method is only a proxy for other parsers, it does not need to do anything with returned nodes. In contrast to that, the `allOf()` method has to compose every node returned from its subparsers to new node. Thanks to that, we can obtain AST instead of CST (concrete syntax tree).
In this example you can notice both `allOf()` and `oneOf()` helper methods. The first one returns success (and parsed node) if and only if all of its subparsers returns success as well. In contrast to that, the `oneOf()` method returns success with parsed node when any of its subparsers returns success. The `oneOf()` method seeks for the first parser that returns success. When it finds it, it immediately returns success with node returned from its subparser and does not execute further subparsers. Because the `oneOf()` method is only a proxy for other parsers, it does not need to do anything with returned nodes. In contrast to that, the `allOf()` method has to compose every node returned from its subparsers to new node. Thanks to that, we can easily obtain AST instead of CST (concrete syntax tree).
This parser implementation can be featured using following notation:
```
parenthesesExpr ::= '(' expr ')' ;
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`.
### 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`.
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:
```kotlin
class SubexpressionParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val expr1Parser = leftAssociativeOperator(
TermParser(),
listOf(TokenType.PLUS, TokenType.MINUS),
assert(TermParser(), "expression")
) { lhs, operator, rhs ->
SumOperatorNode(lhs, operator, rhs)
}
val expr2Parser = leftAssociativeOperator(
expr1Parser,
listOf(TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE),
assert(expr1Parser, "expression")
) { lhs, operator, rhs ->
RelationOperatorNode(lhs, operator, rhs)
}
val expr3Parser = leftAssociativeOperator(
expr2Parser,
listOf(TokenType.AND),
assert(expr2Parser, "expression")
) { lhs, operator, rhs ->
LogicOperatorNode(lhs, operator, rhs)
}
val expr4Parser = leftAssociativeOperator(
expr3Parser,
listOf(TokenType.OR),
assert(expr3Parser, "expression")
) { lhs, operator, rhs ->
LogicOperatorNode(lhs, operator, rhs)
}
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]].
Take a look at the following AST:
```
$ smnp --ast --dry-run -c "true and false or not false and not false;"
```