%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int yylex();
void yyerror(const char* s);
extern FILE* yyin;
%}

%union {
    int num;
    char* str;
}

%token <num> NUMBER ADD SUB MUL DIV MOD
%token <str> IDENTIFIER STRING_LITERAL
%token <str> IF ELSE FOR ASSIGN EQ LT GT LE GE NEQ AND OR NOT SEMICOLON LPAREN RPAREN LBRACE RBRACE PKG MAIN IMPORT FUNC VAR PRINTLN PRINT INT_TYPE

%type <str> program package_declaration import_declaration func_declaration statements statement expression function_call
%type <str> var_declaration print_statement assignment_statement if_statement for_loop expression_list declaration_or_statement

%nonassoc EQ LT GT LE GE NEQ
%left ADD SUB
%left MUL DIV MOD
%left AND
%left OR
%precedence NOT

%%

program:
    declaration_or_statement
    | program declaration_or_statement
    ;

declaration_or_statement:
    var_declaration SEMICOLON
    | print_statement SEMICOLON
    | assignment_statement SEMICOLON
    | import_declaration
    | package_declaration
    | func_declaration
    | if_statement
    | for_loop
    ;

package_declaration:
    PKG MAIN SEMICOLON
    ;

import_declaration:
    IMPORT STRING_LITERAL SEMICOLON
    ;

func_declaration:
    FUNC MAIN LPAREN RPAREN LBRACE statements RBRACE
    ;

statements:
    statement
    | statements statement
    ;

statement:
    declaration_or_statement
    ;

var_declaration:
    VAR IDENTIFIER IDENTIFIER ASSIGN expression
    ;

print_statement:
    PRINTLN LPAREN expression_list RPAREN
    ;

expression_list:
    expression
    | expression_list ',' expression
    ;

assignment_statement:
    IDENTIFIER ASSIGN expression
    ;

if_statement:
    IF LPAREN expression RPAREN LBRACE statements RBRACE
    | IF LPAREN expression RPAREN LBRACE statements RBRACE ELSE LBRACE statements RBRACE
    ;

for_loop:
    FOR LPAREN declaration_or_statement SEMICOLON expression SEMICOLON assignment_statement RPAREN LBRACE statements RBRACE
    ;

expression:
    expression ADD expression {
        int result = atoi($1) + atoi($3);
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);
        $$ = strdup(buffer);}
    | expression SUB expression {
        int result = atoi($1) - atoi($3);
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);
        $$ = strdup(buffer);}
    | expression MUL expression {
        int result = atoi($1) * atoi($3);
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);
        $$ = strdup(buffer);}
    | expression DIV expression {
        int result = atoi($1) / atoi($3);
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);
        $$ = strdup(buffer);}
    | expression MOD expression {
        int result = atoi($1) % atoi($3);
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);
        $$ = strdup(buffer);}
    | expression EQ expression {
        bool result = $1 == $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression LT expression {
        bool result = $1 < $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression GT expression {
        bool result = $1 > $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression LE expression {
        bool result = $1 <= $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression GE expression {
        bool result = $1 >= $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression NEQ expression {
        bool result = $1 != $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression AND expression {
        bool result = $1 && $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | expression OR expression {
        bool result = $1 || $3;
        char* str_result = result ? "true" : "false";
        $$ = strdup(str_result);}
    | NOT expression {
        int result = atoi($2);
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);}
    | ADD expression {$$ = $2;}
    | SUB expression {
        int result = atoi($2);  result = -result;
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);}
    | LPAREN expression RPAREN {$$ = $2;}
    | NUMBER {
        int result = $1;
        char buffer[20];  // Adjust the buffer size as needed
        sprintf(buffer, "%d", result);}
    | IDENTIFIER {printf("identifier: %s\n", $1);}
    | function_call {$$ = $1;}
    ;

function_call:
    IDENTIFIER LPAREN RPAREN {printf("function call: %s\n", $1);}
    | IDENTIFIER LPAREN expression_list RPAREN {printf("function call with arguments: %s\n", $1);}
    ;

%%

void yyerror(const char* s) {
    fprintf(stderr, "%s\n", s);
}

int main() {
    FILE* inputFile = fopen("oddtotal.go", "r");
    if (inputFile == NULL) {
        fprintf(stderr, "Failed to open input file.\n");
        return 1;
    }
    
    yyin = inputFile;
    
    yyparse();
    
    fclose(inputFile);
    return 0;
}
Write some example code which this parser could successfully parse