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

%union {
int num;
char* str;
}

%token <num> NUMBER
%token <str> IDENTIFIER STRING_LITERAL
%token IF ELSE FOR ADD SUB MUL DIV MOD 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 <num> expression arithmetic_expr term factor relational_expr
%type <str> program package_declaration import_declaration func_declaration statements statement var_declaration print_statement assignment_statement if_statement for_loop_initializer for_loop_update function_call
%nonassoc EQ LT GT LE GE NEQ
%left ADD SUB
%left MUL DIV MOD
%left AND
%left OR
%nonassoc NOT UNARY

%%

program:
package_declaration | import_declaration | func_declaration | statements
;

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:var_declaration SEMICOLON
| print_statement SEMICOLON
| assignment_statement SEMICOLON
| if_statement
| for_loop{}
;

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

for_loop:
FOR LPAREN for_loop_initializer SEMICOLON expression SEMICOLON for_loop_update RPAREN LBRACE statements RBRACE
;

for_loop_initializer:
var_declaration
| assignment_statement
;

for_loop_update:
assignment_statement
;

var_declaration:
VAR IDENTIFIER NUMBER ASSIGN expression{}
;

print_statement:
PRINTLN LPAREN expression RPAREN{}
| PRINT LPAREN expression RPAREN{}
;

assignment_statement:
IDENTIFIER ASSIGN expression
;

expression:
relational_expr
;

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

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

factor:
NUMBER {
$$ = $1;}
| IDENTIFIER {printf("identifier: %s\n", $1);}
| LPAREN expression RPAREN {
$$ = $2;}
| SUB factor %prec UNARY {
$$ = -$2;}
| ADD factor %prec UNARY {
$$ = $2;}
| NOT factor %prec UNARY {
$$ = !$2;}
| function_call {
$$ = $1;}
;

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

function_call_arg:
expression{}
| function_call_arg ',' expression
;

relational_expr:
expression EQ expression {
$$ = $1 == $3;}
| expression LT expression {
$$ = $1 < $3;}
| expression GT expression {
$$ = $1 > $3;}
| expression LE expression {
$$ = $1 <= $3;}
| expression GE expression {
$$ = $1 >= $3;}
| expression NEQ expression {
$$ = $1 != $3;}
| expression AND expression {
$$ = $1 && $3;}
| expression OR expression {
$$ = $1 || $3;}
;

%%

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

int main() {
yyparse();
return 0;
}                 gptparser.y:41.1-16: warning: nonterminal useless in grammar: func_declaration [-Wother]
   41 | func_declaration:
      | ^~~~~~~~~~~~~~~~
gptparser.y:45.1-10: warning: nonterminal useless in grammar: statements [-Wother]
   45 | statements:statement
      | ^~~~~~~~~~
gptparser.y:49.1-9: warning: nonterminal useless in grammar: statement [-Wother]
   49 | statement:var_declaration SEMICOLON
      | ^~~~~~~~~
gptparser.y:56.1-12: warning: nonterminal useless in grammar: if_statement [-Wother]
   56 | if_statement:IF LPAREN expression RPAREN LBRACE statements RBRACE{}
      | ^~~~~~~~~~~~
gptparser.y:60.1-8: warning: nonterminal useless in grammar: for_loop [-Wother]
   60 | for_loop:
      | ^~~~~~~~
gptparser.y:64.1-20: warning: nonterminal useless in grammar: for_loop_initializer [-Wother]
   64 | for_loop_initializer:
      | ^~~~~~~~~~~~~~~~~~~~
gptparser.y:69.1-15: warning: nonterminal useless in grammar: for_loop_update [-Wother]
   69 | for_loop_update:
      | ^~~~~~~~~~~~~~~
gptparser.y:73.1-15: warning: nonterminal useless in grammar: var_declaration [-Wother]
   73 | var_declaration:
      | ^~~~~~~~~~~~~~~
gptparser.y:77.1-15: warning: nonterminal useless in grammar: print_statement [-Wother]
   77 | print_statement:
      | ^~~~~~~~~~~~~~~
gptparser.y:82.1-20: warning: nonterminal useless in grammar: assignment_statement [-Wother]
   82 | assignment_statement:
      | ^~~~~~~~~~~~~~~~~~~~
gptparser.y:86.1-10: warning: nonterminal useless in grammar: expression [-Wother]
   86 | expression:
      | ^~~~~~~~~~
gptparser.y:90.1-15: warning: nonterminal useless in grammar: arithmetic_expr [-Wother]
   90 | arithmetic_expr:
      | ^~~~~~~~~~~~~~~
gptparser.y:97.1-4: warning: nonterminal useless in grammar: term [-Wother]
   97 | term:
      | ^~~~
gptparser.y:108.1-6: warning: nonterminal useless in grammar: factor [-Wother]
  108 | factor:
      | ^~~~~~
gptparser.y:124.1-13: warning: nonterminal useless in grammar: function_call [-Wother]
  124 | function_call:
      | ^~~~~~~~~~~~~
gptparser.y:130.1-17: warning: nonterminal useless in grammar: function_call_arg [-Wother]
  130 | function_call_arg:
      | ^~~~~~~~~~~~~~~~~
gptparser.y:135.1-15: warning: nonterminal useless in grammar: relational_expr [-Wother]
  135 | relational_expr:
      | ^~~~~~~~~~~~~~~
gptparser.y:30.44-59: warning: rule useless in grammar [-Wother]
   30 | package_declaration | import_declaration | func_declaration | statements
      |                                            ^~~~~~~~~~~~~~~~
gptparser.y:30.63-72: warning: rule useless in grammar [-Wother]
   30 | package_declaration | import_declaration | func_declaration | statements
      |                                                               ^~~~~~~~~~
gptparser.y:21.1-5: warning: useless precedence and associativity for ADD [-Wprecedence]
   21 | %left ADD SUB
      | ^~~~~
gptparser.y:21.1-5: warning: useless precedence and associativity for SUB [-Wprecedence]
   21 | %left ADD SUB
      | ^~~~~
gptparser.y:22.1-5: warning: useless precedence and associativity for MUL [-Wprecedence]
   22 | %left MUL DIV MOD
      | ^~~~~
gptparser.y:22.1-5: warning: useless precedence and associativity for DIV [-Wprecedence]
   22 | %left MUL DIV MOD
      | ^~~~~
gptparser.y:22.1-5: warning: useless precedence and associativity for MOD [-Wprecedence]
   22 | %left MUL DIV MOD
      | ^~~~~
gptparser.y:20.1-9: warning: useless precedence and associativity for EQ [-Wprecedence]
   20 | %nonassoc EQ LT GT LE GE NEQ
      | ^~~~~~~~~
gptparser.y:20.1-9: warning: useless precedence and associativity for LT [-Wprecedence]
   20 | %nonassoc EQ LT GT LE GE NEQ
      | ^~~~~~~~~
gptparser.y:20.1-9: warning: useless precedence and associativity for GT [-Wprecedence]
   20 | %nonassoc EQ LT GT LE GE NEQ
      | ^~~~~~~~~
gptparser.y:20.1-9: warning: useless precedence and associativity for LE [-Wprecedence]
   20 | %nonassoc EQ LT GT LE GE NEQ
      | ^~~~~~~~~
gptparser.y:20.1-9: warning: useless precedence and associativity for GE [-Wprecedence]
   20 | %nonassoc EQ LT GT LE GE NEQ
      | ^~~~~~~~~
gptparser.y:20.1-9: warning: useless precedence and associativity for NEQ [-Wprecedence]
   20 | %nonassoc EQ LT GT LE GE NEQ
      | ^~~~~~~~~
gptparser.y:23.1-5: warning: useless precedence and associativity for AND [-Wprecedence]
   23 | %left AND
      | ^~~~~
gptparser.y:24.1-5: warning: useless precedence and associativity for OR [-Wprecedence]
   24 | %left OR
      | ^~~~~
gptparser.y:25.1-9: warning: useless precedence and associativity for NOT [-Wprecedence]
   25 | %nonassoc NOT UNARY
      | ^~~~~~~~~
gptparser.y:25.1-9: warning: useless precedence and associativity for UNARY [-Wprecedence]
   25 | %nonassoc NOT UNARY