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

%token IDENTIFIER
%token NUMBER
%token IF
%token ELSE
%token FOR
%token ADD
%token SUB
%token MUL
%token DIV
%token MOD
%token ASSIGN
%token EQ
%token LT
%token GT
%token LE
%token GE
%token NEQ
%token AND
%token OR
%token NOT
%token SEMICOLON
%token LPAREN
%token RPAREN
%token LBRACE
%token RBRACE
%token PACKAGE MAIN IMPORT FUNC VAR PRINTLN PRINT
%token STRING_LITERAL
%token INT
%start program

%%

program:
    package_declaration import_declaration func_declaration
;

package_declaration:
    PACKAGE MAIN SEMICOLON
;

import_declaration:
    IMPORT STRING_LITERAL SEMICOLON
;

func_declaration:
    FUNC MAIN LPAREN RPAREN LBRACE statements RBRACE
;

statements:
    statement
    | statements statement
;

statement:
    | var_declaration SEMICOLON {
        printf("variable declaration and assignment\n");
    }
    | print_statement
    | assignment_statement
    | IF LPAREN expression RPAREN LBRACE statements RBRACE {
        printf("if statement\n");
    }
    | IF LPAREN expression RPAREN LBRACE statements RBRACE ELSE LBRACE statements RBRACE {
        printf("if-else statement\n");
    }
    | FOR LPAREN IDENTIFIER ASSIGN expression SEMICOLON expression SEMICOLON IDENTIFIER ADD ASSIGN expression RPAREN LBRACE statements RBRACE {
        printf("for loop\n");
    }
;

var_declaration:
    VAR IDENTIFIER data_type ASSIGN expression
;

print_statement:
    PRINTLN LPAREN expression RPAREN SEMICOLON {
        printf("println statement\n");
    }
    | PRINT LPAREN expression RPAREN SEMICOLON {
        printf("print statement\n");
    }
;

assignment_statement:
    IDENTIFIER ASSIGN expression SEMICOLON {
        printf("%d = %d\n", $1, $3);
    }
;

data_type:
    INT
;

expression:
    expression ADD term {
        $$ = $1 + $3;
    }
    | expression SUB term {
        $$ = $1 - $3;
    }
    | term {
        $$ = $1;
    }
;

term:
    term MUL factor {
        $$ = $1 * $3;
    }
    | term DIV factor {
        $$ = $1 / $3;
    }
    | factor {
        $$ = $1;
    }
;

factor:
    NUMBER {
        $$ = $1;
    }
    | IDENTIFIER {
        printf("identifier: %d\n", $1);
    }
    | LPAREN expression RPAREN {
        $$ = $2;
    }
;

%%

int main() {
    yyparse();
    return 0;
}

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

gptparser.y: warning: shift/reduce conflict on token IF [-Wcounterexamples]
  Example: • IF LPAREN expression RPAREN LBRACE RBRACE
  Shift derivation
    statements
    ↳ 5: statement
         ↳ 11: • IF LPAREN expression RPAREN LBRACE statements RBRACE
                                                    ↳ 11: ε
  Reduce derivation
    statements
    ↳ 6: statements     statement
         ↳ 5: statement ↳ 11: IF LPAREN expression RPAREN LBRACE statements RBRACE
              ↳ 7: ε • 