typedef enum token_kind {
    TK_BEGIN, TK_END, TK_LOCALS, TK_GOTO, TK_IF, TK_RETURN, TK_COMMA, TK_LPAREN, TK_RPAREN, TK_EQUALS, TK_NEWLINE, TK_IDENTIFIER, TK_INTEGER, TK_PLUS, TK_MINUS, TK_STAR, TK_DIVIDE, TK_MODULO, TK_COLON, TK_LESS_THAN, TK_GREATER_THAN, TK_AMPERSAND, TK_BANG,
    N_TOKEN_KINDS
} Token_Kind;
extern const char *token_kind_names[N_TOKEN_KINDS];
extern const char *token_kind_literals[N_TOKEN_KINDS];
typedef struct token {
    Token_Kind kind;
    char *text;
    int line;
    int column;
} Token;
typedef struct token_list {
    Token *data;
    int size;
    int capacity;
} Token_List;
Token_List new_token_list(void);
void free_token_list(Token_List tl);
void print_token_list(Token_List tl);
void append_token_to_list(Token_List *tl, Token token);
typedef struct lex_result {
    _Bool ok;
    Token token;
} Lex_Result;
typedef Lex_Result(*Lexer)(char *);
Token_List lex(char *input);
typedef enum statement_kind {
    SK_ASSIGNMENT, SK_ARITHMETIC, SK_CALL, SK_LABEL, SK_GOTO, SK_IF, SK_REFERENCE, SK_ASSIGNMENT_DEREFERENCE, SK_DEREFERENCE_ASSIGNMENT,
    N_STATEMENT_KINDS
} Statement_Kind;
extern const char *statement_kind_names[N_STATEMENT_KINDS];
const char *name_for_statement_kind(Statement_Kind kind);
typedef enum value_kind {
    VK_INTEGER, VK_IDENTIFIER,
    N_VALUE_KINDS
} Value_Kind;
extern const char *value_kind_names[N_VALUE_KINDS];
const char *name_for_value_kind(Value_Kind kind);
typedef enum arithmetic_operator {
    ARITHOP_PLUS, ARITHOP_MINUS, ARITHOP_MULTIPLY, ARITHOP_DIVIDE, ARITHOP_MODULO,
    N_ARITHMETIC_OPERATOR_KINDS
} Arithmetic_Operator;
extern const char *arithop_names[N_ARITHMETIC_OPERATOR_KINDS];
const char *name_for_arithop(Arithmetic_Operator op);
typedef enum relational_operator {
    RELOP_LESS_THAN, RELOP_GREATER_THAN, RELOP_EQUAL, RELOP_LE, RELOP_GE, RELOP_NE,
    N_RELATIONAL_OPERATOR_KINDS
} Relational_Operator;
extern const char *relop_names[N_RELATIONAL_OPERATOR_KINDS];
const char *name_for_relop(Relational_Operator op);
typedef struct integer {
    int value;
} Integer;
typedef struct identifier {
    char *text;
} Identifier;
typedef struct identifier_list {
    Identifier *data;
    int size;
    int capacity;
} Identifier_List;
typedef struct value {
    Value_Kind kind;
    union {
        Integer integer;
        Identifier identifier;
    };
} Value;
typedef struct value_list {
    Value *data;
    int size;
    int capacity;
} Value_List;
typedef struct deference_assignment {
    Identifier left_hand_side;
    Value right_hand_side;
} Dereference_Assignment;
typedef struct assignment_dereference {
    Identifier left_hand_side;
    Identifier right_hand_side;
} Assignment_Dereference;
typedef struct reference {
    Identifier left_hand_side;
    Identifier right_hand_side;
} Reference;
typedef struct return_ {
    Value value;
} Return;
typedef struct if_ {
    Value left_operand;
    Relational_Operator operator;
    Value right_operand;
    Identifier name;
} If;
typedef struct goto_ {
    Identifier name;
} Goto;
typedef struct label {
    Identifier name;
} Label;
typedef struct call {
    Identifier left_hand_side;
    Identifier function_name;
    Value_List arguments;
} Call;
typedef struct arithmetic {
    Identifier left_hand_side;
    Value left_operand;
    Arithmetic_Operator operator;
    Value right_operand;
} Arithmetic;
typedef struct assignment {
    Identifier left_hand_side;
    Value right_hand_side;
} Assignment;
typedef struct statement {
    Statement_Kind kind;
    union {
        Assignment assignment;
        Arithmetic arithmetic;
        Call call;
        Label label;
        Goto goto_;
        If if_;
        Reference reference;
        Assignment_Dereference assignment_dereference;
        Dereference_Assignment dereference_assignment;
    };
} Statement;
typedef struct statement_list {
    Statement *data;
    int size;
    int capacity;
} Statement_List;
typedef struct function {
    Identifier name;
    Identifier_List parameters;
    Identifier_List locals;
    Statement_List body;
    Return return_;
} Function;
typedef struct program {
    Function function;
} Program;
Program parse(Token_List token_list);
void free_program(Program program);
void print_program(Program program);
