rbnf 0.3.21
context sensitive grammar parser generator for CPython
License: MIT
Requires Python: >=3.6.0
Keywords: parser-generator,context-sensitive,ebnf


RBNF: Parser Generator for Context Sensitive Grammars
==========================================================

[![Build Status](https://travis-ci.org/thautwarm/RBNF.svg?branch=master)](https://travis-ci.org/thautwarm/RBNF)
[![PyPI version](https://img.shields.io/pypi/v/RBNF.svg)](https://pypi.python.org/pypi/rbnf)
[![MIT License](https://img.shields.io/badge/license-MIT-Green.svg?style=flat)](https://github.com/thautwarm/RBNF/blob/master/LICENSE)

Tutorials
---------------

See [Jupyter Notebook](https://github.com/thautwarm/RBNF/blob/master/tutorials.ipynb).

Preview
---------------

- `rbnf.zero`: solution to processing complex texts. Similar to `re`.

    See source file [Poly.rbnf](https://github.com/thautwarm/RBNF/blob/master/tests/poly.rbnf).

    ```python
    # parse polynomials from text.
    import rbnf.zero as ze
    ze_exp = ze.compile("import poly.[*]", use='Poly')
    print(ze_exp.match("2x^2 + 3 + 4 - 7 x^5 + 4 x + 5 x ^2 - x + 7 x ^ 11").result)
    ```

    Then we got output `[(0, 7), (1, 3), (2, 7), (5, -7), (11, 7)]`.

- `CLI tool chains`:

     ```shell

     λ rbnf.exe --help
    Available commands:
      cc
          rbnf source code compiler.

      - filename(positional or keyword arg)        : input source file
      - output(positional or keyword arg) = None   : output file name. default to be ...
      - name(positional or keyword arg) = 'unname' : name of language

      run
          You can apply immediate tests on your parser.
          P.S: use `--opt` option takes longer starting time.

      - filename(positional or keyword arg)    : python file generated by `rbnf` command, or rbnf sour file
      - opt(positional or keyword arg) = False : optimize switch



    λ printf "ignore [space]\nspace := R'\s+'\nterm := R'[^\s\(\)]+'\nsexpr ::= '(' sexpr* ')' | term" > lisp.rbnf
    λ rbnf run lisp

    type `:i` to switch between python mode and parsing mode.
    The last result of parsing is stored as symbol `res`.

    runbnf> (add 1 (add 2))

    sexpr[
           Tokenizer(name='auto_const', value='(', lineno=0, colno=0)
           sexpr[
                 Tokenizer(name='term', value='add', lineno=0, colno=1)
           ]
           sexpr[
                 Tokenizer(name='term', value='1', lineno=0, colno=5)
           ]
           sexpr[
                  Tokenizer(name='auto_const', value='(', lineno=0, colno=7)
                  sexpr[
                        Tokenizer(name='term', value='add', lineno=0, colno=8)
                  ]
                  sexpr[
                        Tokenizer(name='term', value='2', lineno=0, colno=12)
                  ]
                  Tokenizer(name='auto_const', value=')', lineno=0, colno=13)
           ]
           Tokenizer(name='auto_const', value=')', lineno=0, colno=14)
    ]

    runbnf> exit

     λ rbnf cc lisp.bnf -output lisp.py
     ...
     ```

Related
----------------------

- RBNF could help to develop type checker:

   [https://github.com/thautwarm/reFining](https://github.com/thautwarm/reFining])

   ```
   python cli.py

   reF> let x: 'a = 1 in
         fn x: 'a -> x ;;
   =>  (int`2 => int`2)
   ```

- RBNF could help to develop programming languages:

    [https://github.com/thautwarm/rmalt](https://github.com/thautwarm/rmalt)

    ```
    python test.py

    malt> let (%+) = (l, r) -> (l + r) % r;;
    malt> let f = (a, b) -> a  + b;;
    malt> f 1 2;;
    =>  3
    malt> f 1
          ;;
    =>  Fn(b)<id=3061211909288>
    malt> infix %+ 5;;
    =>  5
    malt> let (%+) = (l, r) -> (l % r) + r;;
    malt> 5 %+ 6;;
    =>  11

    ```


EDSL in Python
---------------------


**To be continue**.


`RBNF`'s compiler(rbnf -> python or others) relies on bootstrap.

Actually, in current version, bootstrap of RBNF is implemented in EDSL.

See [rbnf bootstrap in Python](https://github.com/thautwarm/RBNF/blob/master/rbnf/bootstrap/rbnf.py).

A snippet could be previewed here.

```python

rbnf = Language("RBNF")

...

@rbnf
class Primitive(Parser):

    @classmethod
    def bnf(cls):
        # @formatter:off
        return optimize(
                 C('(') + Or @ "or_" + C(')')
               | C('[') + Or @ "optional" + C(']')
               | Name @ "name"
               | Str  @ "str")
        # @formatter:on

     @classmethod
    def rewrite(cls, state: State):
        get = state.ctx.get
        or_: Parser = get('or_')
        optional: Parser = get('optional')
        ...

...

```


Other backend
----------------

To be continue.