let token_to_string = function
    | SPACE(n) -> "SPACE(" ^ string_of_int n ^ ")"
    | COLON -> "COLON"
    | NEWLINE -> "NEWLINE"
    | THIS -> "THIS"
    | ARRAY -> "ARRAY"
    | REFINABLE -> "REFINABLE"
    | AND -> "AND"
    | OR -> "OR"
    | XOR -> "XOR"
    | NAND -> "NAND"
    | NOR -> "NOR"
    | NOT -> "NOT"
    | EQ -> "EQ"
    | NEQ -> "NEQ"
    | LT -> "LT"
    | LEQ -> "LEQ"
    | GT -> "GT"
    | GEQ -> "GEQ"
    | LBRACKET -> "LBRACKET"
    | RBRACKET -> "RBRACKET"
    | LPAREN -> "LPAREN"
    | RPAREN -> "RPAREN"
    | LBRACE -> "LBRACE"
    | RBRACE -> "RBRACE"
    | SEMI -> "SEMI"
    | COMMA -> "COMMA"
    | PLUS -> "PLUS"
    | MINUS -> "MINUS"
    | TIMES -> "TIMES"
    | DIVIDE -> "DIVIDE"
    | MOD -> "MOD"
    | POWER -> "POWER"
    | PLUSA -> "PLUSA"
    | MINUSA -> "MINUSA"
    | TIMESA -> "TIMESA"
    | DIVIDEA -> "DIVIDEA"
    | MODA -> "MODA"
    | POWERA -> "POWERA"
    | IF -> "IF"
    | ELSE -> "ELSE"
    | ELSIF -> "ELSIF"
    | WHILE -> "WHILE"
    | RETURN -> "RETURN"
    | CLASS -> "CLASS"
    | EXTEND -> "EXTEND"
    | SUPER -> "SUPER"
    | INIT -> "INIT"
    | NULL -> "NULL"
    | VOID -> "VOID"
    | REFINE -> "REFINE"
    | REFINES -> "REFINES"
    | TO -> "TO"
    | PRIVATE -> "PRIVATE"
    | PUBLIC -> "PUBLIC"
    | PROTECTED -> "PROTECTED"
    | DOT -> "DOT"
    | MAIN -> "MAIN"
    | NEW -> "NEW"
    | ASSIGN -> "ASSIGN"
    | ID(vid) -> Printf.sprintf "ID(%s)" vid
    | TYPE(tid) -> Printf.sprintf "TYPE(%s)" tid
    | BLIT(bool) -> Printf.sprintf "BLIT(%B)" bool
    | ILIT(inum) -> Printf.sprintf "ILIT(%d)" inum
    | FLIT(fnum) -> Printf.sprintf "FLIT(%f)" fnum
    | SLIT(str) -> Printf.sprintf "SLIT(\"%s\")" (str)
    | EOF -> "EOF"