aboutsummaryrefslogtreecommitdiff
path: root/grammars/bp.bp
blob: 27829349af408eece34f1ae3406c81b00635fee7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# This is a file defining the BP grammar using BP syntax
#
# This is a complete definition of the grammar of BP grammar files, but it's
# mainly intended to be used as a proof-of-concept, and a stress-test for BP.
# The grammar files provided with BP are not otherwise intended to be full
# language grammars.

Grammar: __ *(Def [__`;])%__ __ [@error=(+(./\n) => "Could not parse this code: @0")]
Def: @name=id __ `: __ (
      @definition=extended-pat
    / $$ @error=(=>"No definition for rule")
    / @error=(..%\n>(`;/id_`:/$) => "Invalid definition: @0"))

# This is used for command line arguments:
String-pattern: ..%(\n / Nodent / Identifier-char / Identifier-start / Escape / `\ pat [`;])$$

pat: simple-pat !(__("!~"/"~")) / suffixed-pat
simple-pat: (Upto-and / Dot / Word-boundary/ String / Chars / Nodent / Curdent
    / Identifier-char / Identifier-start / Escape-range
    / Escape / Repeat / Optional / No / After / Before / Capture
    / Start-of-File / Start-of-Line / End-of-File / End-of-Line / Ref / parens)

suffixed-pat: (
      Match-pat
    / Not-match-pat
)

Match-pat: @first=(suffixed-pat / simple-pat)__"~"__@second=(pat / @error=(=>"Expected pattern after '~'"))
Not-match-pat: @first=(suffixed-pat / simple-pat)__"!~"__@second=(pat / @error=(=>"Expected pattern after '!~'"))

Dot: `. !`.
String: (
        `" @s=.. (`" / $ @error=(=>"Expected closing quote here"))
      / `' @s=.. (`' / $ @error=(=>"Expected closing quote here"))
    )
Chars: `` @+(Char-range/Char) % `,
Char-range: @low=. `- (@high=. / @error=(=>"Expected a second character to form a character range"))
Char: (@s=. / @error=(=>"Expected a character following the '`'"))
Escape-range: `\ @low=escape-sequence `- @high=escape-sequence
Escape: `\ (@s=escape-sequence
    / $ @error=(=>"Backslashes are used for escape sequences, not splitting lines")
    / @error=(. *(Abc/`0-9) => "Invalid escape sequence: '@0'")
)
escape-sequence: (
       `n,t,r,e,b,a,v
      / 1-3 `0-7
      / `x 2 `0-9,a-f,A-F
    )
No: `! (__@pat / @error=(=>"Expected a pattern after the exclamation mark"))
Nodent: "\N"
Curdent: "\C"
Word-boundary: `| / "\b"
Identifier-char: "\i"
Identifier-start: "\I"
Upto-and: ".." [__(`%/`=)__@second=simple-pat] [__@first=simple-pat]
Repeat: (
        @min=(=>'0') (`*=>"-") @max=(=>'∞')
      / @min=int __ `- __ @max=int
      / @min=(int / =>'1') __ (`+=>"-") @max=(=>'∞')
      / @min=@max=int
    ) __ @repeat-pat=pat [__`%__@sep=pat]
Optional: `[ __ extended-pat (__`] / @error=(=>"Expected closing square bracket here"))
After: `< __ pat
Before: `> __ pat
Capture: `@ [__ @capture-name=(id/`!) __ !"=>" `=] __ (@capture=pat / @error=(=>"Expected pattern to capture"))
Replace: (
      @replace-pat=[Chain-noreplace / pat] __ "=>" (__ @replacement=String / @error=(=>"Expected replacement string"))
    )
Replace-chain: Replace-chain __ "=>" (__ @replacement=String / @error=(=>"Expected replacement string"))
Empty-replacement: (
       (=>"EMPTY") @replace-pat=(=>"''") "=>" (__ @replacement=String / @error=(=>"Expected replacement string"))
    )
Ref: @name=id !(__`:)
Start-of-File: "^^"
Start-of-Line: "^"
End-of-File: "$$"
End-of-Line: "$"

parens: `( __ extended-pat (__ `) / @error=(=>"Expected closing parenthesis here"))

Chain: @(Replace/pat) __ @(Chain/Replace/pat)
Chain-noreplace: @pat __ @(Chain-noreplace/pat)
Otherwise: 2+@(Chain / Replace / pat)%(__`/__)
extended-pat: Otherwise / Chain / Replace / pat

# Special-symbol rules:
_:  *(`  / \t)
__: *(`  / \t / \r / \n / comment)

id: "__" / "_" / `a-z,A-Z *`a-z,A-Z,0-9,-

comment: `# .. $