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 EXPR ::= | ADDSUB ADDSUB ::= MULDIVMOD ((add|sub) MULDIVMOD)* MULDIVMOD ::= LITERAL ((mul|div|mod) LITERAL)* LITERAL ::= | ident | int | CALL CALL ::= ident opar ARGS cpar ARGS ::= (EXPR (comma EXPR)*)?