PROG ::= INSTR* INSTR ::= | DIR | EXPR semicolon | FUNDECL | return EXPR semicolon | EXTERN semicolon EXTERN ::= extern fun ident opar PARAMS cpar RET FUNDECL ::= fun ident opar PARAMS cpar RET BLOCK PARAMS ::= (ident type? (comma ident type?)*) RET ::= type? BLOCK ::= obrace INSTR* cbrace DIR ::= hash ident EXPR (as ident)? EXPR ::= | ADDSUB ADDSUB ::= MULDIVMOD ((add|sub) MULDIVMOD)* MULDIVMOD ::= LITERAL ((mul|div|mod) LITERAL)* LITERAL ::= | ident | int | CALL | NS CALL ::= ident opar ARGS cpar ARGS ::= (EXPR (comma EXPR)*)? NS ::= ident (dot (ident|CALL))+