c2lang / c2compiler

the c2 programming language
c2lang.org
Apache License 2.0
702 stars 47 forks source link

Grammar railroad diagram #126

Open mingodad opened 1 week ago

mingodad commented 1 week ago

On https://github.com/c3lang/c3c/blob/master/resources/grammar/grammar.y they have a fully working grammar using bison/flex and that can be used to make a C2lang grammar.

Another option is to use the EBNF generated from that grammar that can be understood by (IPV4) https://rr.red-dove.com/ui or (IPV6) https://www.bottlecaps.de/rr/ui to also trim down/expand to a c2lang grammar with a nice navigable railroad diagram (see instructions bellow at the top).

//
// EBNF to be viewd at
//    (IPV6) https://www.bottlecaps.de/rr/ui
//    (IPV4) https://rr.red-dove.com/ui
//
// Copy and paste this at one of the urls shown above in the 'Edit Grammar' tab
// then click the 'View Diagram' tab.
//
/* converted on Mon Sep 16, 2024, 15:37 (UTC+02) by bison-to-w3c v0.68-SNAPSHOT which is Copyright (c) 2011-2024 by Gunther Rademacher <grd@gmx.net> */

start_here ::= translation_unit // to navigate from the top

path     ::= ( IDENT SCOPE )+

path_const ::= path? CONST_IDENT

path_ident ::= path? IDENT

path_at_ident ::= path? AT_IDENT

ident_expr ::= CONST_IDENT
    | IDENT
    | AT_IDENT

local_ident_expr ::= CT_IDENT
    | HASH_IDENT

ct_call  ::= CT_ALIGNOF
    | CT_EXTNAMEOF
    | CT_NAMEOF
    | CT_OFFSETOF
    | CT_QNAMEOF

ct_castable ::= CT_ASSIGNABLE

ct_analyse ::= CT_EVAL
    | CT_SIZEOF
    | CT_STRINGIFY
    | CT_IS_CONST

ct_vaarg ::= CT_VACONST
    | CT_VAARG
    | CT_VAREF
    | CT_VAEXPR

flat_path ::= primary_expr param_path?
    | type

maybe_optional_type ::= optional_type
    | /*empty*/

string_expr ::= STRING_LITERAL+

expr_block ::= LBRAPIPE opt_stmt_list RBRAPIPE

base_expr ::= string_expr
    | INTEGER
    | BYTES+
    | NUL
    | CHAR_LITERAL
    | REAL
    | TRUE
    | FALSE
    | base_expr_assignable

base_expr_assignable ::= BUILTIN ( CONST_IDENT | IDENT )
    | path? ident_expr
    | local_ident_expr
    | type ( initializer_list | '.' ( access_ident | CONST_IDENT ) )
    | ( '(' expr | ct_call '(' flat_path | ct_analyse '(' expression_list | CT_DEFINED '(' arg_list | CT_FEATURE '(' CONST_IDENT | ct_castable '(' expr ',' type ) ')'
    | expr_block
    | ct_vaarg '[' expr ']'
    | CT_VACOUNT
    | lambda_decl compound_statement

primary_expr ::= base_expr
    | initializer_list

range_loc ::= '^'? expr

range_expr ::= ( range_loc ( DOTDOT | ':' ) | DOTDOT ) range_loc?
    | ':' range_loc

call_invocation ::= '(' call_arg_list ')' AT_IDENT*

access_ident ::= IDENT
    | AT_IDENT
    | HASH_IDENT
    | CT_EVAL '(' expr ')'
    | TYPEID

call_trailing ::= '[' ( range_loc | range_expr ) ']'
    | call_invocation compound_statement?
    | '.' access_ident
    | generic_expr
    | INC_OP
    | DEC_OP
    | '!'
    | BANGBANG

call_expr ::= primary_expr call_trailing*

unary_expr ::= unary_op* call_expr

unary_stmt_expr ::= base_expr_assignable call_trailing*
    | unary_op unary_expr

unary_op ::= '&'
    | AND_OP
    | '*'
    | '+'
    | '-'
    | '~'
    | '!'
    | INC_OP
    | DEC_OP
    | '(' type ')'

mult_op  ::= '*'
    | '/'
    | '%'

mult_expr ::= unary_expr ( mult_op unary_expr )*

shift_op ::= SHL_OP
    | SHR_OP

shift_expr ::= mult_expr ( shift_op mult_expr )*

bit_op   ::= '&'
    | '^'
    | '|'

bit_expr ::= shift_expr ( bit_op shift_expr )*

additive_op ::= '+'
    | '-'
    | CT_CONCAT_OP

additive_expr ::= bit_expr ( additive_op bit_expr )*

relational_op ::= '<'
    | '>'
    | LE_OP
    | GE_OP
    | EQ_OP
    | NE_OP

relational_expr ::= additive_expr ( relational_op additive_expr )*

try_catch_rhs_expr ::= call_expr
    | lambda_decl IMPLIES relational_expr

try_chain_expr ::= ( lambda_decl IMPLIES )? relational_expr

and_expr ::= relational_expr ( ( AND_OP | CT_AND_OP ) relational_expr )*

or_expr  ::= and_expr ( ( OR_OP | CT_OR_OP ) and_expr )*

or_stmt_expr ::= unary_stmt_expr ( mult_op unary_expr )* ( shift_op mult_expr )* ( bit_op shift_expr )* ( additive_op bit_expr )* ( relational_op additive_expr )* ( ( AND_OP | CT_AND_OP ) relational_expr )* ( ( OR_OP | CT_OR_OP ) and_expr )*

suffix_expr ::= or_expr ( '?' '!'? )?

suffix_stmt_expr ::= or_stmt_expr ( '?' '!'? )?

ternary_expr ::= ( or_expr '?' expr ':' | suffix_expr ( ELVIS | OPTELSE ) )* ( suffix_expr | lambda_decl implies_body )

ternary_stmt_expr ::= suffix_stmt_expr ( ( ELVIS | OPTELSE ) ternary_expr )?
    | or_stmt_expr '?' expr ':' ternary_expr
    | lambda_decl implies_body

assignment_op ::= '='
    | ADD_ASSIGN
    | SUB_ASSIGN
    | MUL_ASSIGN
    | DIV_ASSIGN
    | MOD_ASSIGN
    | SHL_ASSIGN
    | SHR_ASSIGN
    | AND_ASSIGN
    | XOR_ASSIGN
    | OR_ASSIGN

assignment_expr ::= ( unary_expr assignment_op )* ( ternary_expr | CT_TYPE_IDENT '=' type )

assignment_stmt_expr ::= ternary_stmt_expr
    | CT_TYPE_IDENT '=' type
    | unary_stmt_expr assignment_op assignment_expr

implies_body ::= IMPLIES expr

lambda_decl ::= FN maybe_optional_type fn_parameter_list opt_attributes

expr_no_list ::= assignment_stmt_expr

expr     ::= assignment_expr

constant_expr ::= ternary_expr

param_path_element ::= '[' expr ( DOTDOT expr )? ']'
    | '.' primary_expr

param_path ::= param_path_element+

arg_name ::= IDENT
    | CT_TYPE_IDENT
    | HASH_IDENT
    | CT_IDENT

arg      ::= param_path ( '=' ( expr | type ) )?
    | arg_name ':' ( expr | type )
    | type
    | ELLIPSIS? expr
    | CT_VASPLAT ( '[' range_expr ']' )?

arg_list ::= arg ( ',' arg? )*

opt_arg_list ::= arg_list
    | /*empty*/

call_arg_list ::= opt_arg_list ( ';' parameters? )?

opt_interface_impl ::= '(' ( TYPE_IDENT opt_generic_parameters ( ',' TYPE_IDENT opt_generic_parameters )* )? ')'
    | /*empty*/

enum_constants ::= enum_constant ( ',' enum_constant )*

enum_list ::= enum_constants ','?

enum_constant ::= CONST_IDENT opt_attributes ( '=' constant_expr )?

enum_param_decl ::= type IDENT

base_type ::= VOID
    | BOOL
    | CHAR
    | ICHAR
    | SHORT
    | USHORT
    | INT
    | UINT
    | LONG
    | ULONG
    | INT128
    | UINT128
    | FLOAT
    | DOUBLE
    | FLOAT16
    | BFLOAT16
    | FLOAT128
    | IPTR
    | UPTR
    | ISZ
    | USZ
    | ANYFAULT
    | ANY
    | TYPEID
    | path? TYPE_IDENT opt_generic_parameters
    | CT_TYPE_IDENT
    | ( CT_TYPEOF '(' expr | ( CT_TYPEFROM | CT_EVALTYPE ) '(' constant_expr ) ')'
    | CT_VATYPE '[' constant_expr ']'

type     ::= base_type ( '*' | '[' ( constant_expr | '*' )? ']' | LVEC ( constant_expr | '*' ) RVEC )*

optional_type ::= type '!'?

local_decl_after_type ::= CT_IDENT ( '=' constant_expr )?
    | IDENT opt_attributes ( '=' expr )?

local_decl_storage ::= STATIC
    | TLOCAL

decl_or_expr ::= var_decl
    | optional_type local_decl_after_type
    | expr

var_decl ::= VAR ( IDENT '=' expr | CT_IDENT ( '=' expr )? | CT_TYPE_IDENT ( '=' type )? )

initializer_list ::= '{' opt_arg_list '}'

ct_case_stmt ::= ( CT_CASE ( constant_expr | type ) | CT_DEFAULT ) ':' opt_stmt_list

ct_for_stmt ::= CT_FOR '(' for_cond ')' opt_stmt_list CT_ENDFOR

ct_foreach_stmt ::= CT_FOREACH '(' CT_IDENT ( ',' CT_IDENT )? ':' expr ')' opt_stmt_list CT_ENDFOREACH

ct_switch ::= CT_SWITCH ( '(' ( constant_expr | type ) ')' )?

ct_switch_stmt ::= ct_switch ct_case_stmt+ CT_ENDSWITCH

var_stmt ::= var_decl ';'

decl_stmt_after_type ::= local_decl_after_type ( ',' local_decl_after_type )*

declaration_stmt ::= const_declaration
    | local_decl_storage? optional_type decl_stmt_after_type ';'

return_stmt ::= RETURN expr? ';'

catch_unwrap_list ::= relational_expr ( ',' relational_expr )*

catch_unwrap ::= CATCH ( type? IDENT '=' )? catch_unwrap_list

try_unwrap ::= TRY ( try_catch_rhs_expr | type? IDENT '=' try_chain_expr )

try_unwrap_chain ::= try_unwrap ( AND_OP ( try_unwrap | try_chain_expr ) )*

default_stmt ::= DEFAULT ':' opt_stmt_list

case_stmt ::= CASE ( expr ( DOTDOT expr )? | type ) ':' opt_stmt_list

switch_body ::= ( case_stmt | default_stmt )+

cond_repeat ::= decl_or_expr ( ',' decl_or_expr )*

cond     ::= try_unwrap_chain
    | catch_unwrap
    | cond_repeat ( ',' ( try_unwrap_chain | catch_unwrap ) )?

else_part ::= ELSE ( if_stmt | compound_statement )

if_stmt  ::= IF optional_label paren_cond ( '{' switch_body '}' else_part? | statement | compound_statement else_part )

expr_list_eos ::= expression_list? ';'

cond_eos ::= cond? ';'

for_cond ::= expr_list_eos cond_eos expression_list?

for_stmt ::= FOR optional_label '(' for_cond ')' statement

paren_cond ::= '(' cond ')'

while_stmt ::= WHILE optional_label paren_cond statement

do_stmt  ::= DO optional_label compound_statement ( WHILE '(' expr ')' )? ';'

optional_label_target ::= CONST_IDENT
    | /*empty*/

continue_stmt ::= CONTINUE optional_label_target ';'

break_stmt ::= BREAK optional_label_target ';'

nextcase_stmt ::= NEXTCASE ( ( CONST_IDENT ':' )? ( expr | type | DEFAULT ) )? ';'

foreach_var ::= optional_type? '&'? IDENT

foreach_vars ::= foreach_var ( ',' foreach_var )?

foreach_stmt ::= ( FOREACH | FOREACH_R ) optional_label '(' foreach_vars ':' expr ')' statement

defer_stmt ::= DEFER ( TRY | CATCH | '(' CATCH IDENT ')' )? statement

ct_if_stmt ::= CT_IF constant_expr ':' opt_stmt_list ( CT_ELSE opt_stmt_list )? CT_ENDIF

assert_stmt ::= ASSERT '(' expr ( ',' expr )* ')' ';'

asm_stmts ::= asm_stmt+

asm_instr ::= ( INT | IDENT ) ( '.' IDENT )?

asm_addr ::= asm_expr ( additive_op asm_expr ( ( '*' ( INTEGER additive_op )? | shift_op | additive_op ) INTEGER )? )?

asm_expr ::= CT_IDENT
    | CT_CONST_IDENT
    | '&'? IDENT
    | CONST_IDENT
    | REAL
    | INTEGER
    | '(' expr ')'
    | '[' asm_addr ']'

asm_stmt ::= asm_instr ( asm_expr ( ',' asm_expr )* )? ';'

asm_block_stmt ::= ASM ( '(' constant_expr ')' AT_IDENT? ';' | AT_IDENT? '{' asm_stmts? '}' )

statement ::= compound_statement
    | var_stmt
    | declaration_stmt
    | return_stmt
    | if_stmt
    | while_stmt
    | defer_stmt
    | switch_stmt
    | do_stmt
    | for_stmt
    | foreach_stmt
    | continue_stmt
    | break_stmt
    | nextcase_stmt
    | asm_block_stmt
    | ct_echo_stmt
    | ct_assert_stmt
    | ct_if_stmt
    | ct_switch_stmt
    | ct_foreach_stmt
    | ct_for_stmt
    | expr_no_list? ';'
    | assert_stmt

compound_statement ::= '{' opt_stmt_list '}'

opt_stmt_list ::= statement+
    | /*empty*/

switch_stmt ::= SWITCH optional_label ( paren_cond opt_attributes )? '{' switch_body? '}'

expression_list ::= decl_or_expr ( ',' decl_or_expr )*

optional_label ::= CONST_IDENT ':'
    | /*empty*/

ct_assert_stmt ::= ( CT_ASSERT ( constant_expr ':' )? | CT_ERROR ) constant_expr ';'

ct_include_stmt ::= CT_INCLUDE string_expr ';'

ct_echo_stmt ::= CT_ECHO constant_expr ';'

bitstruct_declaration ::= BITSTRUCT TYPE_IDENT opt_interface_impl ':' type opt_attributes bitstruct_body

bitstruct_body ::= '{' ( bitstruct_def* | ( base_type IDENT ';' )+ ) '}'

bitstruct_def ::= base_type IDENT ':' constant_expr ( DOTDOT constant_expr )? ';'

attribute_name ::= AT_IDENT
    | path? AT_TYPE_IDENT

attribute_operator_expr ::= '&' '[' ']'
    | '[' ']' '='?

attr_param ::= attribute_operator_expr
    | constant_expr

attribute ::= attribute_name ( '(' attr_param ( ',' attr_param )* ')' )?

opt_attributes ::= attribute+
    | /*empty*/

trailing_block_param ::= AT_IDENT ( '(' parameters? ')' )?

macro_params ::= parameters ( ';' trailing_block_param )?
    | ';' trailing_block_param
    | /*empty*/

macro_func_body ::= implies_body ';'
    | compound_statement

macro_declaration ::= MACRO macro_header '(' macro_params ')' opt_attributes macro_func_body

struct_or_union ::= STRUCT
    | UNION

struct_declaration ::= struct_or_union TYPE_IDENT opt_interface_impl opt_attributes struct_body

struct_body ::= '{' struct_member_decl+ '}'

enum_params ::= enum_param_decl ( ',' enum_param_decl )*

struct_member_decl ::= ( type IDENT ( ',' IDENT )* | INLINE type IDENT? ) opt_attributes ';'
    | struct_or_union IDENT? opt_attributes struct_body
    | BITSTRUCT IDENT? ':' type opt_attributes bitstruct_body

enum_spec ::= ':' ( base_type ( '(' enum_params ')' )? | '(' enum_params ')' )

enum_declaration ::= ENUM TYPE_IDENT opt_interface_impl enum_spec? opt_attributes '{' enum_list '}'

faults   ::= CONST_IDENT ( ',' CONST_IDENT )*

fault_declaration ::= FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults ','? '}'

func_macro_name ::= IDENT
    | AT_IDENT

func_header ::= optional_type ( type '.' )? func_macro_name

macro_header ::= func_header
    | ( type '.' )? func_macro_name

fn_parameter_list ::= '(' parameters? ')'

parameter_default ::= parameter ( '=' expr )?

parameters ::= parameter_default ( ',' parameter_default? )*

parameter ::= type ( ( '&'? IDENT | HASH_IDENT )? opt_attributes | ELLIPSIS ( IDENT? opt_attributes | CT_IDENT ) | CT_IDENT )
    | ( '&' IDENT | HASH_IDENT | IDENT ELLIPSIS? ) opt_attributes
    | ELLIPSIS
    | CT_IDENT ELLIPSIS?

func_defintion_decl ::= FN func_header fn_parameter_list opt_attributes ';'

func_definition ::= func_defintion_decl
    | FN func_header fn_parameter_list opt_attributes macro_func_body

const_declaration ::= CONST ( CONST_IDENT opt_attributes '=' expr | type CONST_IDENT opt_attributes ( '=' expr )? ) ';'

func_typedef ::= FN optional_type fn_parameter_list

opt_inline ::= INLINE
    | /*empty*/

typedef_type ::= func_typedef
    | type

global_storage ::= TLOCAL
    | /*empty*/

global_declaration ::= global_storage optional_type IDENT ( opt_attributes ( '=' expr )? | ( ',' IDENT )+ opt_attributes ) ';'

define_attribute ::= AT_TYPE_IDENT ( '(' parameters ')' )? opt_attributes '=' '{' opt_attributes '}'

generic_expr ::= LGENPAR ( expr | type ) ( ',' ( expr | type ) )* RGENPAR

opt_generic_parameters ::= generic_expr
    | /*empty*/

define_ident ::= ( IDENT '=' path_ident | CONST_IDENT '=' path_const | AT_IDENT '=' path_at_ident ) opt_generic_parameters

define_declaration ::= DEF ( define_ident | define_attribute | TYPE_IDENT opt_attributes '=' typedef_type ) opt_attributes ';'

interface_declaration ::= INTERFACE TYPE_IDENT '{' func_defintion_decl* '}'

distinct_declaration ::= DISTINCT TYPE_IDENT opt_interface_impl opt_attributes '=' opt_inline type ';'

module_param ::= CONST_IDENT
    | TYPE_IDENT

module   ::= MODULE path_ident ( LGENPAR module_param ( ',' module_param )* RGENPAR )? opt_attributes ';'

import_decl ::= IMPORT path_ident ( ',' path_ident )* opt_attributes ';'

translation_unit ::= top_level+
    | /*empty*/

opt_extern ::= EXTERN
    | /*empty*/

exec_decl ::= CT_EXEC '(' expr ( ',' initializer_list ( ',' expr )? )? ')' opt_attributes ';'

top_level ::= module
    | import_decl
    | exec_decl
    | opt_extern ( func_definition | const_declaration | global_declaration )
    | ct_assert_stmt
    | ct_echo_stmt
    | ct_include_stmt
    | struct_declaration
    | fault_declaration
    | enum_declaration
    | macro_declaration
    | define_declaration
    | bitstruct_declaration
    | distinct_declaration
    | interface_declaration

//
// Tokens
//

//\("[^"]+"\)\s+{\s*count(); return(\([^)]+\)).+  -> \2 ::= \1
//\(\S+\)\s+\(\S+\)  -> \2 ::= \1

CT_ALIGNOF ::= "$alignof"
CT_ASSERT ::= "$assert"
CT_ASSIGNABLE ::= "$assignable"
CT_CASE ::= "$case"
CT_DEFAULT ::= "$default"
CT_DEFINED ::= "$defined"
CT_ECHO ::= "$echo"
CT_ELSE ::= "$else"
CT_ENDFOR ::= "$endfor"
CT_ENDFOREACH ::= "$endforeach"
CT_ENDIF ::= "$endif"
CT_ENDSWITCH ::= "$endswitch"
CT_ERROR ::= "$error"
CT_EVAL ::= "$eval"
CT_EVALTYPE ::= "$evaltype"
CT_EXEC ::= "$exec"
CT_EXTNAMEOF ::= "$extnameof"
CT_FEATURE ::= "$feature"
CT_FOR ::= "$for"
CT_FOREACH ::= "$foreach"
CT_IF ::= "$if"
CT_IS_CONST ::= "$is_const"
CT_INCLUDE ::= "$include"
CT_NAMEOF ::= "$nameof"
CT_OFFSETOF ::= "$offsetof"
CT_QNAMEOF ::= "$qnameof"
CT_SIZEOF ::= "$sizeof"
CT_STRINGIFY ::= "$stringify"
CT_SWITCH ::= "$switch"
CT_TYPEFROM ::= "$typefrom"
CT_TYPEOF ::= "$typeof"
CT_VAARG ::= "$vaarg"
CT_VACONST ::= "$vaconst"
CT_VACOUNT ::= "$vacount"
CT_VAEXPR ::= "$vaexpr"
CT_VAREF ::= "$varef"
CT_VASPLAT ::= "$vasplat"
CT_VATYPE ::= "$vatype"

ANY ::= "any"
ANYFAULT ::= "anyfault"
ASM ::= "asm"
ASSERT ::= "assert"
BITSTRUCT ::= "bitstruct"
BOOL ::= "bool"
BREAK ::= "break"
CASE ::= "case"
CATCH ::= "catch"
CHAR ::= "char"
CONST ::= "const"
CONTINUE ::= "continue"
DEF ::= "def"
DEFAULT ::= "default"
DEFER ::= "defer"
DISTINCT ::= "distinct"
DO ::= "do"
DOUBLE ::= "double"
ELSE ::= "else"
ENUM ::= "enum"
EXTERN ::= "extern"
FALSE ::= "false"
FAULT ::= "fault"
FLOAT ::= "float"
BFLOAT16 ::= "bfloat16"
FLOAT16 ::= "float16"
FLOAT128 ::= "float128"
FN ::= "fn"
FOR ::= "for"
FOREACH ::= "foreach"
FOREACH_R ::= "foreach_r"
ICHAR ::= "ichar"
IF ::= "if"
IMPORT ::= "import"
INLINE ::= "inline"
INT ::= "int"
INT128 ::= "int128"
IPTR ::= "iptr"
ISZ ::= "isz"
LONG ::= "long"
MACRO ::= "macro"
MODULE ::= "module"
NEXTCASE ::= "nextcase"
NUL ::= "null"
RETURN ::= "return"
SHORT ::= "short"
STRUCT ::= "struct"
STATIC ::= "static"
SWITCH ::= "switch"
TLOCAL ::= "tlocal"
TRUE ::= "true"
TRY ::= "try"
TYPEID ::= "typeid"
UINT ::= "uint"
UINT128 ::= "uint128"
ULONG ::= "ulong"
UNION ::= "union"
UPTR ::= "uptr"
USHORT ::= "ushort"
USZ ::= "usz"
VAR ::= "var"
VOID ::= "void"
WHILE ::= "while"

INTERFACE ::= "interface"
CT_ASSIGNABLE ::= CT_ASSIGNABLE
CT_IS_CONST ::= CT_IS_CONST

ELLIPSIS ::= "..."
DOTDOT ::= ".."
CT_AND_OP ::= "&&&"
CT_OR_OP ::= "|||"
CT_CONCAT_OP ::= "+++"
SHR_ASSIGN ::= ">>="
SHL_ASSIGN ::= "<<="
ADD_ASSIGN ::= "+="
SUB_ASSIGN ::= "-="
MUL_ASSIGN ::= "*="
DIV_ASSIGN ::= "/="
MOD_ASSIGN ::= "%="
AND_ASSIGN ::= "&="
XOR_ASSIGN ::= "^="
OR_ASSIGN ::= "|="
SHR_OP ::= ">>"
SHL_OP ::= "<<"
INC_OP ::= "++"
DEC_OP ::= "--"
AND_OP ::= "&&"
OR_OP ::= "||"
LE_OP ::= "<="
GE_OP ::= ">="
EQ_OP ::= "=="
NE_OP ::= "!="
OPTELSE ::= "??"
SCOPE ::= "::"
ELVIS ::= "?:"
IMPLIES ::= "=>"
LVEC ::= "[<"
RVEC ::= ">]"
LGENPAR ::= "(<"
RGENPAR ::= ">)"
BUILTIN ::= "$$"
BANGBANG ::= "!!"
LBRAPIPE ::= "{|"
RBRAPIPE ::= "|}"
bvdberg commented 1 week ago

I think all people starting to write a language start with bison/yacc/flex. Then they all arrive to the same conclusion; it doesn't really work nicely in that it becomes one big mess. A custom tokenizer with a handwritten parser is much easier and faster, so that's where they all end up :)

What you a clickable EBNF have as advantage?

mingodad commented 1 week ago

What you a clickable EBNF have as advantage? Documentation !