Skip to content

Commit 092ec41

Browse files
leftibotclaude
andauthored
Fix #628: Grammar railroad diagram (#673)
* Fix #628: Add EBNF grammar for railroad diagram generation Add a formal EBNF grammar file (grammar/chaiscript.ebnf) that can be pasted into rr (https://www.bottlecaps.de/rr/ui) to produce navigable railroad diagrams of ChaiScript's syntax. The grammar was validated against the parser implementation and covers all language constructs including class inheritance, guard conditions, raw strings, and const declarations that were missing from the original proposal. A reference section was added to the cheatsheet, and a regression test exercises every documented grammar construct. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address review: add grammar railroad diagram link to README Add a Grammar section to readme.md linking to the EBNF grammar file and to mingodad's railroad diagram generator for direct viewing. Requested by @lefticus in PR #673 review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: leftibot <leftibot@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0fd9cab commit 092ec41

4 files changed

Lines changed: 415 additions & 0 deletions

File tree

cheatsheet.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,3 +915,12 @@ set_print_handler(fun(s) { my_custom_log(s) })
915915

916916
## Extras
917917
ChaiScript itself does not provide a link to the math functions defined in `<cmath>`. You can either add them yourself, or use the [ChaiScript_Extras](https://github.com/ChaiScript/ChaiScript_Extras) helper library. (Which also provides some additional string functions.)
918+
919+
## Grammar Railroad Diagrams
920+
921+
A formal EBNF grammar for ChaiScript is available in [`grammar/chaiscript.ebnf`](grammar/chaiscript.ebnf). You can visualize it as navigable railroad diagrams by pasting its contents into one of these tools:
922+
923+
* [rr — Railroad Diagram Generator (IPv6)](https://www.bottlecaps.de/rr/ui)
924+
* [rr — Railroad Diagram Generator (IPv4)](https://rr.red-dove.com/ui)
925+
926+
Open either link, switch to the **Edit Grammar** tab, paste the file contents, then click **View Diagram**.

grammar/chaiscript.ebnf

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* ChaiScript Grammar — EBNF for Railroad Diagram Generation
3+
*
4+
* View as navigable railroad diagrams at:
5+
* https://www.bottlecaps.de/rr/ui (IPv6)
6+
* https://rr.red-dove.com/ui (IPv4)
7+
*
8+
* Copy and paste this file into the 'Edit Grammar' tab, then
9+
* click 'View Diagram'.
10+
*
11+
* This grammar uses the notation accepted by
12+
* https://github.com/GuntherRademacher/rr :
13+
* - "::=" as rule separator
14+
* - no semicolon at end of rule
15+
* - "?" "+" "*" for repetition
16+
* - C comments
17+
*/
18+
19+
/* ---- Top-level ---- */
20+
21+
statements ::= ( def | try | if | while | class | for
22+
| switch | return | break | continue
23+
| equation | block | eol )+
24+
25+
/* ---- Functions ---- */
26+
27+
def ::= "def" id ( "::" id )? "(" decl_arg_list ")" eol*
28+
( ":" guard )? eol* block
29+
30+
lambda ::= "fun" ( "[" id_arg_list "]" )? "(" decl_arg_list ")" eol* block
31+
32+
guard ::= operator
33+
34+
/* ---- Exception handling ---- */
35+
36+
try ::= "try" eol* block catch* finally?
37+
catch ::= "catch" ( "(" arg ")" )? eol* block
38+
finally ::= "finally" eol* block
39+
40+
/* ---- Control flow ---- */
41+
42+
if ::= "if" "(" equation ( eol equation )? ")" eol* block
43+
( "else" ( if | eol* block ) )*
44+
45+
while ::= "while" "(" operator ")" eol* block
46+
47+
for ::= "for" "(" ( for_guards | equation ":" equation ) ")" eol* block
48+
for_guards ::= equation eol equation eol equation
49+
50+
switch ::= "switch" "(" operator ")" eol* "{" ( case | default )+ "}"
51+
case ::= "case" "(" operator ")" eol* block
52+
default ::= "default" eol* block
53+
54+
/* ---- Classes ---- */
55+
56+
class ::= "class" id ( ":" id )? eol* class_block
57+
class_block ::= "{" class_statements* "}"
58+
class_statements ::= def | var_decl | eol
59+
60+
/* ---- Blocks & flow keywords ---- */
61+
62+
block ::= "{" statements* "}"
63+
return ::= "return" operator?
64+
break ::= "break"
65+
continue ::= "continue"
66+
67+
/* ---- Line termination ---- */
68+
69+
eol ::= "\n" | "\r\n" | ";"
70+
71+
/* ---- Equations & operators ---- */
72+
73+
equation ::= operator ( ( "=" | ":=" | "+=" | "-=" | "*=" | "/="
74+
| "%=" | "<<=" | ">>=" | "&=" | "^=" | "|=" )
75+
equation )?
76+
77+
operator ::= prefix
78+
| value
79+
| operator binary_operator operator
80+
| operator "?" operator ":" operator
81+
82+
prefix ::= ( "++" | "--" | "-" | "+" | "!" | "~" ) operator
83+
84+
binary_operator ::= "||" | "&&"
85+
| "|" | "^" | "&"
86+
| "==" | "!="
87+
| "<" | "<=" | ">" | ">="
88+
| "<<" | ">>"
89+
| "+" | "-"
90+
| "*" | "/" | "%"
91+
92+
/* ---- Values & access ---- */
93+
94+
value ::= var_decl | dot_fun_array | prefix
95+
96+
dot_fun_array ::= ( lambda | num | quoted_string
97+
| single_quoted_string | raw_string
98+
| paren_expression | inline_container
99+
| id )
100+
( fun_call | array_call | dot_access )*
101+
102+
fun_call ::= "(" arg_list ")"
103+
array_call ::= "[" operator "]"
104+
dot_access ::= "." id
105+
106+
/* ---- Variable declarations ---- */
107+
108+
var_decl ::= ( "auto" | "var" | "const" ) ( reference | id )
109+
| "global" ( reference | id )
110+
| "attr" id ( "::" id )?
111+
112+
reference ::= "&" id
113+
114+
/* ---- Parenthesised & inline containers ---- */
115+
116+
paren_expression ::= "(" operator ")"
117+
118+
inline_container ::= "[" container_arg_list "]"
119+
container_arg_list ::= value_range
120+
| map_pair ( "," map_pair )*
121+
| operator ( "," operator )*
122+
123+
value_range ::= operator ".." operator
124+
map_pair ::= operator ":" operator
125+
126+
/* ---- String literals ---- */
127+
128+
quoted_string ::= '"' ( char | escape | interpolation )* '"'
129+
single_quoted_string ::= "'" ( char | escape ) "'"
130+
raw_string ::= 'R"' delimiter? "(" char* ")" delimiter? '"'
131+
delimiter ::= [a-zA-Z0-9_]+
132+
interpolation ::= "${" equation "}"
133+
134+
/* ---- Escape sequences ---- */
135+
136+
escape ::= "\" ( "'" | '"' | "?" | "\" | "a" | "b"
137+
| "f" | "n" | "r" | "t" | "v" | "$"
138+
| "0"
139+
| "x" hex_digit+
140+
| "u" hex_digit hex_digit hex_digit hex_digit
141+
| "U" hex_digit hex_digit hex_digit hex_digit
142+
hex_digit hex_digit hex_digit hex_digit
143+
| octal_digit+ )
144+
145+
/* ---- Argument lists ---- */
146+
147+
id_arg_list ::= id ( "," id )*
148+
decl_arg_list ::= ( arg ( "," arg )* )?
149+
arg_list ::= ( equation ( "," equation )* )?
150+
arg ::= id id?
151+
152+
/* ---- Identifiers ---- */
153+
154+
id ::= ( [a-zA-Z_] [a-zA-Z0-9_]* )
155+
| ( "`" [^`]+ "`" )
156+
| "true" | "false"
157+
| "Infinity" | "NaN"
158+
| "_"
159+
| "__LINE__" | "__FILE__" | "__FUNC__" | "__CLASS__"
160+
161+
/* ---- Numeric literals ---- */
162+
163+
num ::= hex | binary | float | integer
164+
165+
hex ::= "0" ( "x" | "X" ) [0-9a-fA-F]+ int_suffix*
166+
binary ::= "0" ( "b" | "B" ) [01]+ int_suffix*
167+
float ::= [0-9]+ "." [0-9]+ ( ( "e" | "E" ) ( "+" | "-" )? [0-9]+ )? float_suffix?
168+
integer ::= [0-9]+ int_suffix*
169+
170+
int_suffix ::= "l" | "L" | "ll" | "LL" | "u" | "U"
171+
float_suffix ::= "l" | "L" | "f" | "F"
172+
173+
/* ---- Character classes ---- */
174+
175+
octal_digit ::= [0-7]
176+
hex_digit ::= [0-9a-fA-F]
177+
char ::= [^"\]

readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ the doxygen documentation in the build folder or see the website
9191
http://www.chaiscript.com.
9292

9393

94+
Grammar
95+
=======
96+
97+
A formal EBNF grammar for ChaiScript is available in
98+
[grammar/chaiscript.ebnf](grammar/chaiscript.ebnf). To view it as a railroad
99+
diagram, paste the grammar into
100+
[mingodad's railroad diagram generator](https://mingodad.github.io/plgh/json2ebnf.html)
101+
or [bottlecaps.de/rr](https://www.bottlecaps.de/rr/ui).
102+
103+
94104
The shortest complete example possible follows:
95105

96106
```C++

0 commit comments

Comments
 (0)