diff --git a/Application-overview.md b/Application-overview.md index 5c8c5e7..db923ba 100644 --- a/Application-overview.md +++ b/Application-overview.md @@ -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;" ``` \ No newline at end of file