Program -> eof                               // eof | epsilon
Program -> ';'                               // ';'
Program -> Decl ';' Program                  // 'let', 'var'
Program -> Func Program                      // 'func'

Decl -> 'var' identifier DeclVar ';'         // 'var'
Decl -> 'let' identifier DeclLet ';'         // 'let'
Decl -> 'extern' FuncDecl                    // 'extern'
DeclVal -> '=' Expr                          // '='

DeclVar -> ':' 'Int' InitVal                 // ':'
DeclVar -> '=' Expr                          // '='

ValType -> ':' 'Int' InitVal                 // ':'
ValType -> ':' 'Int'                         // ':'

InitVal -> epsilon                           // ';'
InitVal -> '=' Expr                          // '='

Func -> FuncDelc Block                       // 'func'
FuncDecl -> 'func' identifier '(' Args ')' RetType // 'func'

RetType -> epsilon                           // _ | '{', ';'
RetType -> '->' RetType_                     // '->'
RetType_ -> 'Void'                           // 'Void'
RetType_ -> 'Int'                            // 'Int'

Block -> '{' Block_ '}'                      // '{'
Block_ -> epsilon                            // _ | '}'
Block_ -> Decl ';' Block_                    // 'var' | '}'
Block_ -> Expr ';' Block_                    // identifier, number_literal, '(' | '}'
Block_ -> Stmt Block_                        // 'for', 'while', 'if' | '}'

Expr          -> AssignExpr                  // '(', identifier, number_literal, '-', '!',  '['

AssignExpr    -> LogExpr AssignExpr_         // '(', identifier, number_literal, '-', '!',  '['
AssignExpr_   -> epsilon                     // _ | '..', '...', ')', '{', ']', ',', ';'
AssignExpr_   -> '=' Expr                    // '='

LogExpr       -> ArithAddExpr LogExpr_       // '(', identifier, number_literal, '-', '!',  '['
LogExpr_      -> epsilon                     // _ | '=', ')', ';'
LogExpr_      -> LogOp ArithAddExpr          // '==', '!=', '<', '>', '<=', '>='

ArithAddExpr  -> ArithMulExpr ArithAddExpr_  // '(', identifier, number_literal, '-', '!',  '['
ArithAddExpr_ -> epsilon                     // _ | '==', '!=', '<', '>', '<=', '>=', '=', '..', '...', ')', '{', ']', ',', ';'
ArithAddExpr_ -> AddOp ArithMulExpr          // '+', '-'

ArithMulExpr  -> PrimaryExpr ArithMulExpr_   // '(', identifier, number_literal, '-', '!',  '['
ArithMulExpr_ -> epsilon                     // _ | '+', '-', '==', '!=', '<', '>', '<=', '>=', '=', '..', '...', ')', '{', ']', ',', ';'
ArithMulExpr_ -> MulOp PrimaryExpr           // '*', '/', '%'

PrimaryExpr   -> '(' Expr ')'                // '('
PrimaryExpr   -> identiier IdExpr            // identifier
PrimaryExpr   -> number_literal              // number_literal
PrimaryExpr   -> ArrayLiteral                // '['
PrimaryExpr   -> '-' PrimaryExpr             // '-'
PrimaryExpr   -> '!' PrimaryExpr             // '!'

IdExpr        -> epsilon                     // _ | '*', '/', '%', '+', '-', '==', '!=', '<', '>', '<=', '>=', '=', '..', '...', ')', '{', ']', ',', ';'
IdExpr        -> FuncCall                    // '('
IdExpr        -> Subscript                   // '['


Stmt -> For                                  // 'for'
Stmt -> While                                // 'while'
Stmt -> If                                   // 'if'

FuncCall -> '(' Args ')'                     // '('
Subscript -> '[' Expr ']'                    // '['

ExprPattern -> '(' ExprPattern_ ')'          // '('
ExprPattern_ -> epsilon                      // _ | ')'
ExprPattern_ -> Expr ExprPattern__           // identifier, number_literal, '('
ExprPattern__ -> epsilon                     // ')'
ExprPattern__ -> ',' Expr ExprPattern__      // ','

VarPattern -> '(' VarPattern_ ')'            // '('
VarPattern_ -> epsilon                       // ')'
VarPattern_ -> identifier: Int VarPattern__  // identifier
VarPattern__ -> epsilon                      // ')'
VarPattern__ -> ',' identifier               // ','
                VarPattern__


For -> 'for' identifier 'in' Range Block     // 'for'
While -> 'while' Expr Block                  // 'while'
If -> 'if' Expr Block Else                   // 'if'
Else -> epsilon                              // _ | 'var', identifier, number_literal, '(', 'for', 'while', 'if', '}'
Else -> 'else' Block                         // 'else'

Args -> epsilon                              // _ | ')'
Args -> identifier Args_                     // identifier
Args_ -> epsilon                             // _ | ')'
Args_ -> ',' identifier Args_                // ','

ArrayLiteral -> '[' Expr ArrayBody ']'       // '['
ArrayBody -> epsilon                         // _ | ']'
ArrayBody -> Expr ',' ArrayBody              // '(', identifier, number_literal, '-', '!',  '['

Range -> Expr Range_                         // identifier, number_literal, '('
Range_ -> '..' Expr                          // '..'
Range_ -> '...' Expr                         // '...'