grammar ANF; aexp : 'true' #true | 'false' # false | IDENT #var | NUMBER #num | STRING #str | '(' aexp '+' aexp ')' #add | '(' aexp '-' aexp ')' #sub | '(' aexp '*' aexp ')' #mul | '(' aexp '/' aexp ')' #div | '(' aexp '>' aexp ')' #gt | '(' aexp '<' aexp ')' #lt | '(' aexp '==' aexp ')' #eq | '(' aexp '<<' aexp ')' #bsl | '(' aexp '>>' aexp ')' #bsr | '(' aexp '&&' aexp ')' #and | '(' aexp '||' aexp ')' #or | '(' aexp '^^' aexp ')' #xor | '(' IDENT (',' IDENT)* ':' cexp ')' #lam ; funcall : IDENT '(' aexp (',' aexp)* ')' #call | aexp #atom ; cexp : 'let' IDENT '=' funcall 'in' cexp #let | 'if' aexp 'then' cexp 'else' cexp #if | funcall #fc ; IDENT: Letter (Letter | Digit)*; NUMBER: Digit+; STRING: '"' ([^"]|'\\'.)* '"'; fragment Letter: 'A' .. 'Z' | 'a' .. 'z'; fragment Digit: '0'..'9'; WS: [ \t\n\r]+ -> skip;