Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grammar railroad diagram #167

Open
mingodad opened this issue Jun 28, 2021 · 4 comments
Open

Grammar railroad diagram #167

mingodad opened this issue Jun 28, 2021 · 4 comments

Comments

@mingodad
Copy link

I've done a experimental tool to convert bison grammars to a kind of EBNF understood by https://www.bottlecaps.de/rr/ui to generate railroad diagrams see bellow the converted interpreter/text/parser.mly and with some hand made changes to allow view it at https://www.bottlecaps.de/rr/ui the order of the rules could be changed to a better view of the railroad diagrams. Copy and paste the EBNF bellow on https://www.bottlecaps.de/rr/ui tab Edit Grammar then switch to the tab View Diagram.

/*
From https://github.com/WebAssembly/exception-handling/blob/master/interpreter/text/parser.mly
*/

name ::= /*empty*/ | STRING
string_list ::= /*empty*/ | | string_list STRING
ref_kind ::= /*empty*/ | FUNC | EXTERN
ref_type ::= /*empty*/ | FUNCREF | EXTERNREF
value_type ::= /*empty*/ | NUM_TYPE | ref_type
value_type_list ::= /*empty*/ | | value_type value_type_list
global_type ::= /*empty*/ | value_type | LPAR MUT value_type RPAR
def_type ::= /*empty*/ | LPAR FUNC func_type RPAR
func_type ::= /*empty*/ | | LPAR RESULT value_type_list RPAR func_type | LPAR PARAM value_type_list RPAR func_type | LPAR PARAM bind_var value_type RPAR func_type
table_type ::= /*empty*/ | limits ref_type
memory_type ::= /*empty*/ | limits
limits ::= /*empty*/ | NAT | NAT NAT
type_use ::= /*empty*/ | LPAR TYPE var RPAR
num ::= /*empty*/ | NAT | INT | FLOAT
var ::= /*empty*/ | NAT | VAR
var_list ::= /*empty*/ | | var var_list
bind_var_opt ::= /*empty*/ | | bind_var
bind_var ::= /*empty*/ | VAR
labeling_opt ::= /*empty*/ | | bind_var
labeling_end_opt ::= /*empty*/ | | bind_var
offset_opt ::= /*empty*/ | | OFFSET_EQ_NAT
align_opt ::= /*empty*/ | | ALIGN_EQ_NAT
instr ::= /*empty*/ | plain_instr | select_instr_instr | call_instr_instr | block_instr | expr
plain_instr ::= /*empty*/ | UNREACHABLE | NOP | DROP | BR var | BR_IF var | BR_TABLE var var_list | RETURN | CALL var | THROW var | RETHROW var | LOCAL_GET var | LOCAL_SET var | LOCAL_TEE var | GLOBAL_GET var | GLOBAL_SET var | TABLE_GET var | TABLE_SET var | TABLE_SIZE var | TABLE_GROW var | TABLE_FILL var | TABLE_COPY var var | TABLE_INIT var var | TABLE_GET | TABLE_SET | TABLE_SIZE | TABLE_GROW | TABLE_FILL | TABLE_COPY | TABLE_INIT var | ELEM_DROP var | LOAD offset_opt align_opt | STORE offset_opt align_opt | MEMORY_SIZE | MEMORY_GROW | MEMORY_FILL | MEMORY_COPY | MEMORY_INIT var | DATA_DROP var | REF_NULL ref_kind | REF_IS_NULL | REF_FUNC var | CONST num | TEST | COMPARE | UNARY | BINARY | CONVERT
select_instr ::= /*empty*/ | SELECT select_instr_results
select_instr_results ::= /*empty*/ | LPAR RESULT value_type_list RPAR select_instr_results |
select_instr_instr ::= /*empty*/ | SELECT select_instr_results_instr
select_instr_results_instr ::= /*empty*/ | LPAR RESULT value_type_list RPAR select_instr_results_instr | instr
call_instr ::= /*empty*/ | CALL_INDIRECT var call_instr_type | CALL_INDIRECT call_instr_type
call_instr_type ::= /*empty*/ | type_use call_instr_params | call_instr_params
call_instr_params ::= /*empty*/ | LPAR PARAM value_type_list RPAR call_instr_params | call_instr_results
call_instr_results ::= /*empty*/ | LPAR RESULT value_type_list RPAR call_instr_results |
call_instr_instr ::= /*empty*/ | CALL_INDIRECT var call_instr_type_instr | CALL_INDIRECT call_instr_type_instr
call_instr_type_instr ::= /*empty*/ | type_use call_instr_params_instr | call_instr_params_instr
call_instr_params_instr ::= /*empty*/ | LPAR PARAM value_type_list RPAR call_instr_params_instr | call_instr_results_instr
call_instr_results_instr ::= /*empty*/ | LPAR RESULT value_type_list RPAR call_instr_results_instr | instr
block_instr ::= /*empty*/ | BLOCK labeling_opt block END labeling_end_opt | LOOP labeling_opt block END labeling_end_opt | IF labeling_opt block END labeling_end_opt | IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt | TRY labeling_opt block handler_instr | TRY labeling_opt block DELEGATE var
block ::= /*empty*/ | type_use block_param_body | block_param_body
block_param_body ::= /*empty*/ | block_result_body | LPAR PARAM value_type_list RPAR block_param_body
block_result_body ::= /*empty*/ | instr_list | LPAR RESULT value_type_list RPAR block_result_body
handler_instr ::= /*empty*/ | catch_list_instr END | catch_list_instr catch_all END | catch_all END | END
catch_list_instr ::= /*empty*/ | catch catch_list_instr | catch
handler ::= /*empty*/ | catch_list | catch_list LPAR catch_all RPAR | LPAR catch_all RPAR | LPAR DELEGATE var RPAR |
catch_list ::= /*empty*/ | catch_list LPAR catch RPAR | LPAR catch RPAR
catch ::= /*empty*/ | CATCH var instr_list
catch_all ::= /*empty*/ | CATCH_ALL instr_list
expr ::= /*empty*/ | LPAR expr1 RPAR
expr1 ::= /*empty*/ | plain_instr expr_list | SELECT select_expr_results | CALL_INDIRECT var call_expr_type | CALL_INDIRECT call_expr_type | BLOCK labeling_opt block | LOOP labeling_opt block | IF labeling_opt if_block | TRY labeling_opt try_block
select_expr_results ::= /*empty*/ | LPAR RESULT value_type_list RPAR select_expr_results | expr_list
call_expr_type ::= /*empty*/ | type_use call_expr_params | call_expr_params
call_expr_params ::= /*empty*/ | LPAR PARAM value_type_list RPAR call_expr_params | call_expr_results
call_expr_results ::= /*empty*/ | LPAR RESULT value_type_list RPAR call_expr_results | expr_list
if_block ::= /*empty*/ | type_use if_block_param_body | if_block_param_body
if_block_param_body ::= /*empty*/ | if_block_result_body | LPAR PARAM value_type_list RPAR if_block_param_body
if_block_result_body ::= /*empty*/ | if_ | LPAR RESULT value_type_list RPAR if_block_result_body
if_ ::= /*empty*/ | expr if_ | LPAR THEN instr_list RPAR LPAR ELSE instr_list RPAR | LPAR THEN instr_list RPAR
try_block ::= /*empty*/ | type_use try_block_param_body | try_block_param_body
try_block_param_body ::= /*empty*/ | try_block_result_body | LPAR PARAM value_type_list RPAR try_block_param_body
try_block_result_body ::= /*empty*/ | try_ | LPAR RESULT value_type_list RPAR try_block_result_body
try_ ::= /*empty*/ | LPAR DO instr_list RPAR handler
instr_list ::= /*empty*/ | | select_instr | call_instr | instr instr_list
expr_list ::= /*empty*/ | | expr expr_list
const_expr ::= /*empty*/ | instr_list
func ::= /*empty*/ | LPAR FUNC bind_var_opt func_fields RPAR
func_fields ::= /*empty*/ | type_use func_fields_body | func_fields_body | inline_import type_use func_fields_import | inline_import func_fields_import | inline_export func_fields
func_fields_import ::= /*empty*/ | func_fields_import_result | LPAR PARAM value_type_list RPAR func_fields_import | LPAR PARAM bind_var value_type RPAR func_fields_import
func_fields_import_result ::= /*empty*/ | | LPAR RESULT value_type_list RPAR func_fields_import_result
func_fields_body ::= /*empty*/ | func_result_body | LPAR PARAM value_type_list RPAR func_fields_body | LPAR PARAM bind_var value_type RPAR func_fields_body
func_result_body ::= /*empty*/ | func_body | LPAR RESULT value_type_list RPAR func_result_body
func_body ::= /*empty*/ | instr_list | LPAR LOCAL value_type_list RPAR func_body | LPAR LOCAL bind_var value_type RPAR func_body
table_use ::= /*empty*/ | LPAR TABLE var RPAR
memory_use ::= /*empty*/ | LPAR MEMORY var RPAR
offset ::= /*empty*/ | LPAR OFFSET const_expr RPAR | expr
elem_kind ::= /*empty*/ | FUNC
elem_expr ::= /*empty*/ | LPAR ITEM const_expr RPAR | expr
elem_expr_list ::= /*empty*/ | | elem_expr elem_expr_list
elem_var_list ::= /*empty*/ | var_list
elem_list ::= /*empty*/ | elem_kind elem_var_list | ref_type elem_expr_list
elem ::= /*empty*/ | LPAR ELEM bind_var_opt elem_list RPAR | LPAR ELEM bind_var_opt table_use offset elem_list RPAR | LPAR ELEM bind_var_opt DECLARE elem_list RPAR | LPAR ELEM bind_var_opt offset elem_list RPAR | LPAR ELEM bind_var_opt offset elem_var_list RPAR
table ::= /*empty*/ | LPAR TABLE bind_var_opt table_fields RPAR
table_fields ::= /*empty*/ | table_type | inline_import table_type | inline_export table_fields | ref_type LPAR ELEM elem_var_list RPAR | ref_type LPAR ELEM elem_expr elem_expr_list RPAR
data ::= /*empty*/ | LPAR DATA bind_var_opt string_list RPAR | LPAR DATA bind_var_opt memory_use offset string_list RPAR | LPAR DATA bind_var_opt offset string_list RPAR
memory ::= /*empty*/ | LPAR MEMORY bind_var_opt memory_fields RPAR
memory_fields ::= /*empty*/ | memory_type | inline_import memory_type | inline_export memory_fields | LPAR DATA string_list RPAR
event ::= /*empty*/ | LPAR EVENT bind_var_opt event_fields RPAR
event_fields ::= /*empty*/ | type_use func_type | func_type | inline_import type_use event_fields_import | inline_import event_fields_import | inline_export event_fields
event_fields_import ::= /*empty*/ | event_fields_import_result | LPAR PARAM value_type_list RPAR event_fields_import | LPAR PARAM bind_var value_type RPAR event_fields_import
event_fields_import_result ::= /*empty*/ | | LPAR RESULT value_type_list RPAR event_fields_import_result
global ::= /*empty*/ | LPAR GLOBAL bind_var_opt global_fields RPAR
global_fields ::= /*empty*/ | global_type const_expr | inline_import global_type | inline_export global_fields
import_desc ::= /*empty*/ | LPAR FUNC bind_var_opt type_use RPAR | LPAR FUNC bind_var_opt func_type RPAR | LPAR TABLE bind_var_opt table_type RPAR | LPAR MEMORY bind_var_opt memory_type RPAR | LPAR EVENT bind_var_opt type_use RPAR | LPAR EVENT bind_var_opt func_type RPAR | LPAR GLOBAL bind_var_opt global_type RPAR
import ::= /*empty*/ | LPAR IMPORT name name import_desc RPAR
inline_import ::= /*empty*/ | LPAR IMPORT name name RPAR
export_desc ::= /*empty*/ | LPAR FUNC var RPAR | LPAR TABLE var RPAR | LPAR MEMORY var RPAR | LPAR EVENT var RPAR | LPAR GLOBAL var RPAR
export ::= /*empty*/ | LPAR EXPORT name export_desc RPAR
inline_export ::= /*empty*/ | LPAR EXPORT name RPAR
type_ ::= /*empty*/ | def_type
type_def ::= /*empty*/ | LPAR TYPE type_ RPAR | LPAR TYPE bind_var type_ RPAR
start ::= /*empty*/ | LPAR START var RPAR
module_fields ::= /*empty*/ | | module_fields1
module_fields1 ::= /*empty*/ | type_def module_fields | global module_fields | table module_fields | memory module_fields | event module_fields | func module_fields | elem module_fields | data module_fields | start module_fields | import module_fields | export module_fields
module_var_opt ::= /*empty*/ | | VAR
module_ ::= /*empty*/ | LPAR MODULE module_var_opt module_fields RPAR
inline_module ::= /*empty*/ | module_fields
inline_module1 ::= /*empty*/ | module_fields1
script_var_opt ::= /*empty*/ | | VAR
script_module ::= /*empty*/ | module_ | LPAR MODULE module_var_opt BIN string_list RPAR | LPAR MODULE module_var_opt QUOTE string_list RPAR
action ::= /*empty*/ | LPAR INVOKE module_var_opt name const_list RPAR | LPAR GET module_var_opt name RPAR
assertion ::= /*empty*/ | LPAR ASSERT_MALFORMED script_module STRING RPAR | LPAR ASSERT_INVALID script_module STRING RPAR | LPAR ASSERT_UNLINKABLE script_module STRING RPAR | LPAR ASSERT_TRAP script_module STRING RPAR | LPAR ASSERT_RETURN action result_list RPAR | LPAR ASSERT_TRAP action STRING RPAR | LPAR ASSERT_EXCEPTION action RPAR | LPAR ASSERT_EXHAUSTION action STRING RPAR
cmd ::= /*empty*/ | action | assertion | script_module | LPAR REGISTER name module_var_opt RPAR | meta
cmd_list ::= /*empty*/ | | cmd cmd_list
meta ::= /*empty*/ | LPAR SCRIPT script_var_opt cmd_list RPAR | LPAR INPUT script_var_opt STRING RPAR | LPAR OUTPUT script_var_opt STRING RPAR | LPAR OUTPUT script_var_opt RPAR
const ::= /*empty*/ | LPAR CONST num RPAR | LPAR REF_NULL ref_kind RPAR | LPAR REF_EXTERN NAT RPAR
const_list ::= /*empty*/ | | const const_list
result ::= /*empty*/ | const | LPAR CONST NAN RPAR | LPAR REF_FUNC RPAR | LPAR REF_EXTERN RPAR
result_list ::= /*empty*/ | | result result_list
script ::= /*empty*/ | cmd_list EOF | inline_module1 EOF
script1 ::= /*empty*/ | cmd
module1 ::= /*empty*/ | module_ EOF | inline_module EOF

// Tokens

LPAR  ::= "("
RPAR  ::= ")"

EXTERN  ::= "extern"
EXTERNREF  ::= "externref"
FUNCREF  ::= "funcref"
MUT  ::= "mut"

REF_NULL  ::= "ref.null"
REF_FUNC  ::= "ref.func"
REF_EXTERN  ::= "ref.extern"
REF_IS_NULL  ::= "ref.is_null"

NOP  ::= "nop"
UNREACHABLE  ::= "unreachable"
DROP  ::= "drop"
BLOCK  ::= "block"
LOOP  ::= "loop"
END  ::= "end"
BR  ::= "br"
BR_IF  ::= "br_if"
BR_TABLE  ::= "br_table"
RETURN  ::= "return"
IF  ::= "if"
THEN  ::= "then"
ELSE  ::= "else"
SELECT  ::= "select"
CALL  ::= "call"
CALL_INDIRECT  ::= "call_indirect"

LOCAL_GET  ::= "local.get"
LOCAL_SET  ::= "local.set"
LOCAL_TEE  ::= "local.tee"
GLOBAL_GET  ::= "global.get"
GLOBAL_SET  ::= "global.set"

TABLE_GET  ::= "table.get"
TABLE_SET  ::= "table.set"
TABLE_SIZE  ::= "table.size"
TABLE_GROW  ::= "table.grow"
TABLE_FILL  ::= "table.fill"
TABLE_COPY  ::= "table.copy"
TABLE_INIT  ::= "table.init"
ELEM_DROP  ::= "elem.drop"

MEMORY_SIZE  ::= "memory.size"
MEMORY_GROW  ::= "memory.grow"
MEMORY_FILL  ::= "memory.fill"
MEMORY_COPY  ::= "memory.copy"
MEMORY_INIT  ::= "memory.init"
DATA_DROP  ::= "data.drop"

TRY  ::= "try"
DO  ::= "do"
CATCH  ::= "catch"
CATCH_ALL  ::= "catch_all"
DELEGATE  ::= "delegate"
THROW  ::= "throw"
RETHROW  ::= "rethrow"

TYPE  ::= "type"
FUNC  ::= "func"
START  ::= "start"
PARAM  ::= "param"
RESULT  ::= "result"
LOCAL  ::= "local"
GLOBAL  ::= "global"
TABLE  ::= "table"
MEMORY  ::= "memory"
EVENT  ::= "event"
ELEM  ::= "elem"
DATA  ::= "data"
DECLARE  ::= "declare"
OFFSET  ::= "offset"
ITEM  ::= "item"
IMPORT  ::= "import"
EXPORT  ::= "export"

MODULE  ::= "module"
BIN  ::= "binary"
QUOTE  ::= "quote"

SCRIPT  ::= "script"
REGISTER  ::= "register"
INVOKE  ::= "invoke"
GET  ::= "get"
ASSERT_MALFORMED  ::= "assert_malformed"
ASSERT_INVALID  ::= "assert_invalid"
ASSERT_UNLINKABLE  ::= "assert_unlinkable"
ASSERT_RETURN  ::= "assert_return"
ASSERT_TRAP  ::= "assert_trap"
ASSERT_EXCEPTION  ::= "assert_exception"
ASSERT_EXHAUSTION  ::= "assert_exhaustion"
NAN Script.CanonicalNan  ::= "nan:canonical"
NAN Script.ArithmeticNan  ::= "nan:arithmetic"
INPUT  ::= "input"
OUTPUT  ::= "output"
@rossberg
Copy link
Member

Very cute!

Question: I'm a bit confused about all the /*empty*/ productions you inserted everywhere, and which seem to make the grammar incorrect. What are they for?

Also, there appears to be some oversimplification of func_type, which now allows params and results to occur in any order. Similarly with the locals in functions, which can be interleaved with instructions.

@mingodad
Copy link
Author

Thank you for pointing this out /*empty*/ this is inserted by the tool I made because in bison grammars any rule that starts with | mean the first option is /*empty*/ and looking throut the grammas now I can see that this is not the case with menhir grammars ?

I'll review the menhir grammar.

@mingodad
Copy link
Author

mingodad commented Jun 28, 2021

After some work I found easier to replace ::= /*empty*/ | by ::= and then replace ::= | to ::= /*empty*/ |, see the result bellow:

/*
From https://github.com/WebAssembly/exception-handling/blob/master/interpreter/text/parser.mly
*/

name ::=  STRING
string_list ::=  /* empty */ | string_list STRING
ref_kind ::=  FUNC | EXTERN
ref_type ::=  FUNCREF | EXTERNREF
value_type ::=  NUM_TYPE | ref_type
value_type_list ::=  /* empty */ | value_type value_type_list
global_type ::=  value_type | LPAR MUT value_type RPAR
def_type ::=  LPAR FUNC func_type RPAR
func_type ::=  /* empty */ | LPAR RESULT value_type_list RPAR func_type | LPAR PARAM value_type_list RPAR func_type | LPAR PARAM bind_var value_type RPAR func_type
table_type ::=  limits ref_type
memory_type ::=  limits
limits ::=  NAT | NAT NAT
type_use ::=  LPAR TYPE var RPAR
num ::=  NAT | INT | FLOAT
var ::=  NAT | VAR
var_list ::=  /* empty */ | var var_list
bind_var_opt ::=  /* empty */ | bind_var
bind_var ::=  VAR
labeling_opt ::=  /* empty */ | bind_var
labeling_end_opt ::=  /* empty */ | bind_var
offset_opt ::=  /* empty */ | OFFSET_EQ_NAT
align_opt ::=  /* empty */ | ALIGN_EQ_NAT
instr ::=  plain_instr | select_instr_instr | call_instr_instr | block_instr | expr
plain_instr ::=  UNREACHABLE | NOP | DROP | BR var | BR_IF var | BR_TABLE var var_list | RETURN | CALL var | THROW var | RETHROW var | LOCAL_GET var | LOCAL_SET var | LOCAL_TEE var | GLOBAL_GET var | GLOBAL_SET var | TABLE_GET var | TABLE_SET var | TABLE_SIZE var | TABLE_GROW var | TABLE_FILL var | TABLE_COPY var var | TABLE_INIT var var | TABLE_GET | TABLE_SET | TABLE_SIZE | TABLE_GROW | TABLE_FILL | TABLE_COPY | TABLE_INIT var | ELEM_DROP var | LOAD offset_opt align_opt | STORE offset_opt align_opt | MEMORY_SIZE | MEMORY_GROW | MEMORY_FILL | MEMORY_COPY | MEMORY_INIT var | DATA_DROP var | REF_NULL ref_kind | REF_IS_NULL | REF_FUNC var | CONST num | TEST | COMPARE | UNARY | BINARY | CONVERT
select_instr ::=  SELECT select_instr_results
select_instr_results ::=   /* empty */ | LPAR RESULT value_type_list RPAR select_instr_results
select_instr_instr ::=  SELECT select_instr_results_instr
select_instr_results_instr ::=  LPAR RESULT value_type_list RPAR select_instr_results_instr | instr
call_instr ::=  CALL_INDIRECT var call_instr_type | CALL_INDIRECT call_instr_type
call_instr_type ::=  type_use call_instr_params | call_instr_params
call_instr_params ::=  LPAR PARAM value_type_list RPAR call_instr_params | call_instr_results
call_instr_results ::=   /* empty */ | LPAR RESULT value_type_list RPAR call_instr_results
call_instr_instr ::=  CALL_INDIRECT var call_instr_type_instr | CALL_INDIRECT call_instr_type_instr
call_instr_type_instr ::=  type_use call_instr_params_instr | call_instr_params_instr
call_instr_params_instr ::=  LPAR PARAM value_type_list RPAR call_instr_params_instr | call_instr_results_instr
call_instr_results_instr ::=  LPAR RESULT value_type_list RPAR call_instr_results_instr | instr
block_instr ::=  BLOCK labeling_opt block END labeling_end_opt | LOOP labeling_opt block END labeling_end_opt | IF labeling_opt block END labeling_end_opt | IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt | TRY labeling_opt block handler_instr | TRY labeling_opt block DELEGATE var
block ::=  type_use block_param_body | block_param_body
block_param_body ::=  block_result_body | LPAR PARAM value_type_list RPAR block_param_body
block_result_body ::=  instr_list | LPAR RESULT value_type_list RPAR block_result_body
handler_instr ::=  catch_list_instr END | catch_list_instr catch_all END | catch_all END | END
catch_list_instr ::=  catch catch_list_instr | catch
handler ::=   /* empty */ | catch_list | catch_list LPAR catch_all RPAR | LPAR catch_all RPAR | LPAR DELEGATE var RPAR
catch_list ::=  catch_list LPAR catch RPAR | LPAR catch RPAR
catch ::=  CATCH var instr_list
catch_all ::=  CATCH_ALL instr_list
expr ::=  LPAR expr1 RPAR
expr1 ::=  plain_instr expr_list | SELECT select_expr_results | CALL_INDIRECT var call_expr_type | CALL_INDIRECT call_expr_type | BLOCK labeling_opt block | LOOP labeling_opt block | IF labeling_opt if_block | TRY labeling_opt try_block
select_expr_results ::=  LPAR RESULT value_type_list RPAR select_expr_results | expr_list
call_expr_type ::=  type_use call_expr_params | call_expr_params
call_expr_params ::=  LPAR PARAM value_type_list RPAR call_expr_params | call_expr_results
call_expr_results ::=  LPAR RESULT value_type_list RPAR call_expr_results | expr_list
if_block ::=  type_use if_block_param_body | if_block_param_body
if_block_param_body ::=  if_block_result_body | LPAR PARAM value_type_list RPAR if_block_param_body
if_block_result_body ::=  if_ | LPAR RESULT value_type_list RPAR if_block_result_body
if_ ::=  expr if_ | LPAR THEN instr_list RPAR LPAR ELSE instr_list RPAR | LPAR THEN instr_list RPAR
try_block ::=  type_use try_block_param_body | try_block_param_body
try_block_param_body ::=  try_block_result_body | LPAR PARAM value_type_list RPAR try_block_param_body
try_block_result_body ::=  try_ | LPAR RESULT value_type_list RPAR try_block_result_body
try_ ::=  LPAR DO instr_list RPAR handler
instr_list ::=  /* empty */ | select_instr | call_instr | instr instr_list
expr_list ::=  /* empty */ | expr expr_list
const_expr ::=  instr_list
func ::=  LPAR FUNC bind_var_opt func_fields RPAR
func_fields ::=  type_use func_fields_body | func_fields_body | inline_import type_use func_fields_import | inline_import func_fields_import | inline_export func_fields
func_fields_import ::=  func_fields_import_result | LPAR PARAM value_type_list RPAR func_fields_import | LPAR PARAM bind_var value_type RPAR func_fields_import
func_fields_import_result ::=  /* empty */ | LPAR RESULT value_type_list RPAR func_fields_import_result
func_fields_body ::=  func_result_body | LPAR PARAM value_type_list RPAR func_fields_body | LPAR PARAM bind_var value_type RPAR func_fields_body
func_result_body ::=  func_body | LPAR RESULT value_type_list RPAR func_result_body
func_body ::=  instr_list | LPAR LOCAL value_type_list RPAR func_body | LPAR LOCAL bind_var value_type RPAR func_body
table_use ::=  LPAR TABLE var RPAR
memory_use ::=  LPAR MEMORY var RPAR
offset ::=  LPAR OFFSET const_expr RPAR | expr
elem_kind ::=  FUNC
elem_expr ::=  LPAR ITEM const_expr RPAR | expr
elem_expr_list ::=  /* empty */ | elem_expr elem_expr_list
elem_var_list ::=  var_list
elem_list ::=  elem_kind elem_var_list | ref_type elem_expr_list
elem ::=  LPAR ELEM bind_var_opt elem_list RPAR | LPAR ELEM bind_var_opt table_use offset elem_list RPAR | LPAR ELEM bind_var_opt DECLARE elem_list RPAR | LPAR ELEM bind_var_opt offset elem_list RPAR | LPAR ELEM bind_var_opt offset elem_var_list RPAR
table ::=  LPAR TABLE bind_var_opt table_fields RPAR
table_fields ::=  table_type | inline_import table_type | inline_export table_fields | ref_type LPAR ELEM elem_var_list RPAR | ref_type LPAR ELEM elem_expr elem_expr_list RPAR
data ::=  LPAR DATA bind_var_opt string_list RPAR | LPAR DATA bind_var_opt memory_use offset string_list RPAR | LPAR DATA bind_var_opt offset string_list RPAR
memory ::=  LPAR MEMORY bind_var_opt memory_fields RPAR
memory_fields ::=  memory_type | inline_import memory_type | inline_export memory_fields | LPAR DATA string_list RPAR
event ::=  LPAR EVENT bind_var_opt event_fields RPAR
event_fields ::=  type_use func_type | func_type | inline_import type_use event_fields_import | inline_import event_fields_import | inline_export event_fields
event_fields_import ::=  event_fields_import_result | LPAR PARAM value_type_list RPAR event_fields_import | LPAR PARAM bind_var value_type RPAR event_fields_import
event_fields_import_result ::=  /* empty */ | LPAR RESULT value_type_list RPAR event_fields_import_result
global ::=  LPAR GLOBAL bind_var_opt global_fields RPAR
global_fields ::=  global_type const_expr | inline_import global_type | inline_export global_fields
import_desc ::=  LPAR FUNC bind_var_opt type_use RPAR | LPAR FUNC bind_var_opt func_type RPAR | LPAR TABLE bind_var_opt table_type RPAR | LPAR MEMORY bind_var_opt memory_type RPAR | LPAR EVENT bind_var_opt type_use RPAR | LPAR EVENT bind_var_opt func_type RPAR | LPAR GLOBAL bind_var_opt global_type RPAR
import ::=  LPAR IMPORT name name import_desc RPAR
inline_import ::=  LPAR IMPORT name name RPAR
export_desc ::=  LPAR FUNC var RPAR | LPAR TABLE var RPAR | LPAR MEMORY var RPAR | LPAR EVENT var RPAR | LPAR GLOBAL var RPAR
export ::=  LPAR EXPORT name export_desc RPAR
inline_export ::=  LPAR EXPORT name RPAR
type_ ::=  def_type
type_def ::=  LPAR TYPE type_ RPAR | LPAR TYPE bind_var type_ RPAR
start ::=  LPAR START var RPAR
module_fields ::=  /* empty */ | module_fields1
module_fields1 ::=  type_def module_fields | global module_fields | table module_fields | memory module_fields | event module_fields | func module_fields | elem module_fields | data module_fields | start module_fields | import module_fields | export module_fields
module_var_opt ::=  /* empty */ | VAR
module_ ::=  LPAR MODULE module_var_opt module_fields RPAR
inline_module ::=  module_fields
inline_module1 ::=  module_fields1
script_var_opt ::=  /* empty */ | VAR
script_module ::=  module_ | LPAR MODULE module_var_opt BIN string_list RPAR | LPAR MODULE module_var_opt QUOTE string_list RPAR
action ::=  LPAR INVOKE module_var_opt name const_list RPAR | LPAR GET module_var_opt name RPAR
assertion ::=  LPAR ASSERT_MALFORMED script_module STRING RPAR | LPAR ASSERT_INVALID script_module STRING RPAR | LPAR ASSERT_UNLINKABLE script_module STRING RPAR | LPAR ASSERT_TRAP script_module STRING RPAR | LPAR ASSERT_RETURN action result_list RPAR | LPAR ASSERT_TRAP action STRING RPAR | LPAR ASSERT_EXCEPTION action RPAR | LPAR ASSERT_EXHAUSTION action STRING RPAR
cmd ::=  action | assertion | script_module | LPAR REGISTER name module_var_opt RPAR | meta
cmd_list ::=  /* empty */ | cmd cmd_list
meta ::=  LPAR SCRIPT script_var_opt cmd_list RPAR | LPAR INPUT script_var_opt STRING RPAR | LPAR OUTPUT script_var_opt STRING RPAR | LPAR OUTPUT script_var_opt RPAR
const ::=  LPAR CONST num RPAR | LPAR REF_NULL ref_kind RPAR | LPAR REF_EXTERN NAT RPAR
const_list ::=  /* empty */ | const const_list
result ::=  const | LPAR CONST NAN RPAR | LPAR REF_FUNC RPAR | LPAR REF_EXTERN RPAR
result_list ::=  /* empty */ | result result_list
script ::=  cmd_list EOF | inline_module1 EOF
script1 ::=  cmd
module1 ::=  module_ EOF | inline_module EOF

// Tokens

LPAR  ::= "("
RPAR  ::= ")"

EXTERN  ::= "extern"
EXTERNREF  ::= "externref"
FUNCREF  ::= "funcref"
MUT  ::= "mut"

REF_NULL  ::= "ref.null"
REF_FUNC  ::= "ref.func"
REF_EXTERN  ::= "ref.extern"
REF_IS_NULL  ::= "ref.is_null"

NOP  ::= "nop"
UNREACHABLE  ::= "unreachable"
DROP  ::= "drop"
BLOCK  ::= "block"
LOOP  ::= "loop"
END  ::= "end"
BR  ::= "br"
BR_IF  ::= "br_if"
BR_TABLE  ::= "br_table"
RETURN  ::= "return"
IF  ::= "if"
THEN  ::= "then"
ELSE  ::= "else"
SELECT  ::= "select"
CALL  ::= "call"
CALL_INDIRECT  ::= "call_indirect"

LOCAL_GET  ::= "local.get"
LOCAL_SET  ::= "local.set"
LOCAL_TEE  ::= "local.tee"
GLOBAL_GET  ::= "global.get"
GLOBAL_SET  ::= "global.set"

TABLE_GET  ::= "table.get"
TABLE_SET  ::= "table.set"
TABLE_SIZE  ::= "table.size"
TABLE_GROW  ::= "table.grow"
TABLE_FILL  ::= "table.fill"
TABLE_COPY  ::= "table.copy"
TABLE_INIT  ::= "table.init"
ELEM_DROP  ::= "elem.drop"

MEMORY_SIZE  ::= "memory.size"
MEMORY_GROW  ::= "memory.grow"
MEMORY_FILL  ::= "memory.fill"
MEMORY_COPY  ::= "memory.copy"
MEMORY_INIT  ::= "memory.init"
DATA_DROP  ::= "data.drop"

TRY  ::= "try"
DO  ::= "do"
CATCH  ::= "catch"
CATCH_ALL  ::= "catch_all"
DELEGATE  ::= "delegate"
THROW  ::= "throw"
RETHROW  ::= "rethrow"

TYPE  ::= "type"
FUNC  ::= "func"
START  ::= "start"
PARAM  ::= "param"
RESULT  ::= "result"
LOCAL  ::= "local"
GLOBAL  ::= "global"
TABLE  ::= "table"
MEMORY  ::= "memory"
EVENT  ::= "event"
ELEM  ::= "elem"
DATA  ::= "data"
DECLARE  ::= "declare"
OFFSET  ::= "offset"
ITEM  ::= "item"
IMPORT  ::= "import"
EXPORT  ::= "export"

MODULE  ::= "module"
BIN  ::= "binary"
QUOTE  ::= "quote"

SCRIPT  ::= "script"
REGISTER  ::= "register"
INVOKE  ::= "invoke"
GET  ::= "get"
ASSERT_MALFORMED  ::= "assert_malformed"
ASSERT_INVALID  ::= "assert_invalid"
ASSERT_UNLINKABLE  ::= "assert_unlinkable"
ASSERT_RETURN  ::= "assert_return"
ASSERT_TRAP  ::= "assert_trap"
ASSERT_EXCEPTION  ::= "assert_exception"
ASSERT_EXHAUSTION  ::= "assert_exhaustion"
NAN Script.CanonicalNan  ::= "nan:canonical"
NAN Script.ArithmeticNan  ::= "nan:arithmetic"
INPUT  ::= "input"
OUTPUT  ::= "output"

@mingodad
Copy link
Author

Question: I'm a bit confused about all the /*empty*/ productions you inserted everywhere, and which seem to make the grammar incorrect. What are they for?

Also, there appears to be some oversimplification of func_type, which now allows params and results to occur in any order. Similarly with the locals in functions, which can be interleaved with instructions.

I did some fixes (shown on the previous message) could you have a look at it to see if you've pointed out has been resolved ?

One of the objectives of the railroad diagrams is to help visualize the whole grammar and spot possible logical errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants