---
# System prepended metadata

title: Compiler HW2

---

# Compiler HW2


## 問題
* Func_sig 功能的實作
* Lex 裡要多加 ```"\n"         {}``` ，不然總行數(yylineno)會有錯誤
* Casting 的判斷
* 區分int float bool str 的 return
* 

## Token & Type
```c=
/* Token without return */
%token LET MUT NEWLINE
%token <s_val> INT FLOAT BOOL STR
%token TRUE FALSE
%token GEQ LEQ EQL NEQ LOR LAND
%token ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN REM_ASSIGN
%token IF ELSE FOR WHILE LOOP
%token PRINT PRINTLN
%token FUNC RETURN BREAK
%token ARROW AS IN DOTDOT RSHIFT LSHIFT

/* Token with return, which need to sepcify type */
%token <i_val> INT_LIT
%token <f_val> FLOAT_LIT
%token <s_val> STRING_LIT
%token <s_val> ID

/* Nonterminal with return, which need to sepcify type */
%type <i_val> primary_expression_1
%type <f_val> primary_expression_2
%type <s_val> primary_expression_3
%type <s_val> type_specifier
```

## Precedence
```c=
%left LOR
%left LAND
%left EQL NEQ
%left '<' '>' GEQ LEQ
%left LSHIFT RSHIFT
%left '%'
%left '+' '-'
%left '*' '/'
%right '!'
    
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE
```

## Grammar 



```
Grammar1

    0 $accept: Program $end

    1 Program: GlobalStatementList

    2 GlobalStatementList: GlobalStatementList GlobalStatement
    3                    | GlobalStatement

    4 GlobalStatement: FunctionDeclStmt blocks
    5                | NEWLINE

    6 FunctionDeclStmt: function_head '(' parameter_list ')'
    7                 | function_head '(' parameter_list ')' arrow_head

    8 function_head: FUNC ID

    9 arrow_head: ARROW type_specifier

   10 left_mark: '{'

   11 right_mark: '}'

   12 blocks: left_mark statement_list right_mark
   13       | blocks left_mark statement_list right_mark

   14 parameter_list: %empty
   15               | parameter_list_nonempty

   16 parameter_list_nonempty: parameter_declaration
   17                        | parameter_list_nonempty ',' parameter_declaration

   18 parameter_declaration: ID ':' type_specifier

   19 statement_list: %empty
   20               | statement_list statement

   21 statement: declaration ';'
   22          | assignment_statement ';'
   23          | conditional_statement
   24          | loop_statement
   25          | print_statement ';'
   26          | return_statement ';'
   27          | break_statement ';'
   28          | empty_statement
   29          | function_call ';'
   30          | expression
   31          | left_mark statement_list right_mark

   32 function_call: ID '(' term_list ')'

   33 empty_statement: NEWLINE

   34 loop_statement: WHILE expression blocks
   35               | for_loop statement_list right_mark
   36               | LOOP blocks

   37 for_loop: FOR ID IN ID '{'

   38 conditional_statement: IF expression blocks
   39                      | IF expression blocks ELSE blocks

   40 print_statement: PRINT expression
   41                | PRINTLN expression

   42 return_statement: RETURN expression

   43 break_statement: BREAK
   44                | BREAK expression

   45 expression: primary_expression_1
   46           | primary_expression_2
   47           | '"' primary_expression_3 '"'
   48           | term
   49           | expression '+' expression
   50           | expression '-' expression
   51           | expression '*' expression
   52           | expression '/' expression
   53           | expression '%' expression
   54           | expression LSHIFT expression
   55           | expression RSHIFT expression
   56           | expression '<' expression
   57           | expression '>' expression
   58           | expression LEQ expression
   59           | expression GEQ expression
   60           | expression EQL expression
   61           | expression NEQ expression
   62           | expression LAND expression
   63           | expression LOR expression
   64           | '!' expression
   65           | '-' expression
   66           | '(' expression ')'
   67           | '[' expression ']'
   68           | function_call
   69           | TRUE
   70           | FALSE

   71 primary_expression_1: INT_LIT
   72                     | INT_LIT AS type_specifier
   73                     | primary_expression_1 ',' primary_expression_1
   74                     | '[' primary_expression_1 ';' primary_expression_1 ']'

   75 primary_expression_2: FLOAT_LIT
   76                     | FLOAT_LIT AS type_specifier
   77                     | primary_expression_2 ',' primary_expression_2
   78                     | '[' primary_expression_2 ';' primary_expression_1 ']'

   79 primary_expression_3: STRING_LIT
   80                     | %empty

   81 term_list: %empty
   82          | term_list_nonempty

   83 term_list_nonempty: term
   84                   | term_list_nonempty ',' term

   85 term_ID: ID

   86 term_DOTDOT: DOTDOT

   87 term: term_ID
   88     | ID AS type_specifier
   89     | array_term
   90     | '&' term_ID '[' primary_expression_1 term_DOTDOT ']'
   91     | '&' term_ID '[' primary_expression_1 term_DOTDOT primary_expression_1 ']'
   92     | '&' term_ID '[' term_DOTDOT primary_expression_1 ']'

   93 array_term: ID '[' primary_expression_1 ']'
   94           | ID '[' primary_expression_1 ']' '[' primary_expression_1 ']'

   95 type_specifier: INT
   96               | FLOAT
   97               | BOOL
   98               | '&' STR
   99               | '[' type_specifier ';' primary_expression_1 ']'

  100 declaration: LET ID ':' type_specifier '=' expression
  101            | LET ID ':' type_specifier '=' loop_statement
  102            | LET MUT ID ':' type_specifier '=' expression
  103            | LET ID ':' type_specifier
  104            | LET MUT ID ':' type_specifier
  105            | LET ID '=' expression
  106            | LET MUT ID '=' expression

  107 assignment_statement: ID '=' expression
  108                     | ID ADD_ASSIGN expression
  109                     | ID SUB_ASSIGN expression
  110                     | ID MUL_ASSIGN expression
  111                     | ID DIV_ASSIGN expression
  112                     | ID REM_ASSIGN expression
  113                     | array_term '=' expression
  114                     | array_term ADD_ASSIGN expression
  115                     | array_term SUB_ASSIGN expression
  116                     | array_term MUL_ASSIGN expression
  117                     | array_term DIV_ASSIGN expression
  118                     | array_term REM_ASSIGN expression
```



```
Grammar2
```

........

## queue.h
```c=
#ifndef QUEUE_H
#define QUEUE_H

#define NAME_SIZE 64
#include <unistd.h>
#include <stdbool.h>

typedef struct
{
    int index;
    char name[NAME_SIZE];
    int mutable;
    char type[10];
    int address;
    int lineno;
    char func_sig[NAME_SIZE];
    char array_type[10];

} SYMBOL;

struct node
{
    SYMBOL *data;
    struct node *next;
};

struct queue
{
    struct node *head;
    size_t size;
};

SYMBOL *new_symbol(char *name, int index, int mutable, char *type, int address, int lineno, char *func_sig, char *array_type);
typedef struct queue QUEUE;
QUEUE *createQueue(void);
size_t getQsize(const QUEUE *queue);
int enqueue(QUEUE *queue, SYMBOL *element);
void printTable(const QUEUE *queue, int table_index);
void insertMsg(const QUEUE *queue);
void change_func_sig(char *name, const QUEUE *queue, char *type_name);
void change_func_sig_return(char *name, const QUEUE *queue, char *type_name);

QUEUE *tables[100];
QUEUE *parameter_table;
int scope_level;
int address;
char checktype[10];
bool is_first;
char previous_func_name[50];

SYMBOL *find_symbol(char *name, const QUEUE *queue);
SYMBOL *find_symbol_from_all(char *name);

#endif
```


## compiler.l
```c=
/* Definition section */
%{
    #include "compiler_common.h"
    #include "y.tab.h"	/* header file generated by bison */
    extern YYSTYPE yylval;

    #define YY_NO_UNPUT
    #define YY_NO_INPUT
    #define XXX printf("not implemented yet!\n")

    scope_level = 1;
    address = -1;
%}

/* Define regular expression label */
letter [a-zA-Z_]
digit [0-9]
id {letter}+({letter}|{digit})*
inumber {digit}+
fnumber ({digit}*\.{digit}+)

%x CMT
%x STRCOND
%option yylineno

/* Rules section */
%%

"/*"        { BEGIN(CMT); }
<CMT>"*/"   { BEGIN(INITIAL); }
<CMT>\n     {}
<CMT>.      {;}
"//".*      {;}
"\""        { BEGIN(STRCOND);
                return '"';
            }
<STRCOND>"\""   { BEGIN(INITIAL);
                return '"';
            }
<STRCOND>[^\"]* { yylval.s_val = strdup(yytext);
                return STRING_LIT;
            }
"str"       { return STR; }
">>"        { return RSHIFT; }
"<<"        { return LSHIFT; }
"+"         { return '+'; }
"-"         { return '-'; }
"*"         { return '*'; }
"/"         { return '/'; }
"%"         { return '%'; }
">"         { return '>'; }
"<"         { return '<'; }
">="        { return GEQ; }
"<="        { return LEQ; }
"=="        { return EQL; }
"!="        { return NEQ; }
"="         { return '='; }
"+="        { return ADD_ASSIGN; }
"-="        { return SUB_ASSIGN; }
"*="        { return MUL_ASSIGN; }
"/="        { return DIV_ASSIGN; }
"%="        { return REM_ASSIGN; }
"&&"        { return LAND; }
"||"        { return LOR; }
"!"         { return '!'; }
"&"         { return '&'; }
"|"         { return '|'; }
'~'         { return '~'; }
"("         { return '('; }
")"         { return ')'; }
"["         { return '['; }
"]"         { return ']'; }
"{"         { 
                if(scope_level != 1)
                    tables[scope_level] = createQueue();
                else
                    tables[scope_level] = parameter_table;
                scope_level++;
                return '{'; 
            }
"}"         { return '}'; }
":"         { return ':'; }
";"         { return ';'; }
","         { return ','; }
"->"        { return ARROW; }
"print"     { return PRINT; }
"println"   { return PRINTLN; }
"\.\."      { return DOTDOT; }
"as"        { return AS; }
"if"        { return IF; }
"else"      { return ELSE; }
"for"       { return FOR; }
"while"     { return WHILE; }
"loop"      { return LOOP; }
"i32"       { return INT; }
"f32"       { return FLOAT;}
"bool"      { return BOOL; }
"true"      { return TRUE; }
"false"     { return FALSE; }
"fn"        { return FUNC; }
"return"    { return RETURN; }
"let"       { return LET; }
"in"        { return IN; }
"mut"       { return MUT; }
"break"     { return BREAK; }
"\n"         {}
{inumber}   { yylval.i_val = atoi(yytext);
                return INT_LIT;
            }
{fnumber}   { yylval.f_val = atof(yytext);
                return FLOAT_LIT;
            }
{id}        { yylval.s_val = strdup(yytext); return ID;}
<<EOF>>     { static int once = 0;
                if (once++) {
                    yyterminate();
                }
                yylineno++;
                ;
            }
[ \t]+      {;}
%%
/*  C Code section */
int yywrap(void)
{
    return 1;
}
```

## compiler.y
```c=
/* Please feel free to modify any content */

/* Definition section */
%{
    #include "compiler_common.h" //Extern variables that communicate with lex
    #define YYDEBUG 1
    int yydebug = 1;

    extern int yylineno;
    extern int yylex();
    extern FILE *yyin;

    int yylex_destroy ();
    void yyerror (char const *s)
    {
        printf("error:%d: %s\n", yylineno, s);
    }

    extern int yylineno;
    extern int yylex();
    extern FILE *yyin;

    /* Symbol table function - you can add new functions if needed. */
    /* parameters and return type can be changed */
    static void create_symbol(int index);
    static void insert_symbol(char *name, int addr, int mut, char *type, char *func_sig);
    static void lookup_symbol();
    static void dump_symbol();
    static void invalid_oper_msg(int lines, char* op);
    static void undefined_msg(int lines, char* name);

    /* Global variables */
    bool HAS_ERROR = false;
    bool is_print = false;
    SYMBOL* target;

    char print_type[10] = "";
    char array_type[10] = "";
    int round = 0;
    char first_type[10] = "";
    char second_type[10] = "";
    
%}

/* %error-verbose */

/* Use variable or self-defined structure to represent
 * nonterminal and token type
 *  - you can add new fields if needed.
 */
%union {
    int i_val;
    float f_val;
    char *s_val;
    /* ... */
}


/* Token without return */
%token LET MUT NEWLINE
%token INT FLOAT BOOL STR
%token TRUE FALSE
%token GEQ LEQ EQL NEQ LOR LAND
%token ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN REM_ASSIGN
%token IF ELSE FOR WHILE LOOP
%token PRINT PRINTLN
%token FUNC RETURN BREAK
%token ARROW AS IN DOTDOT RSHIFT LSHIFT

/* Token with return, which need to sepcify type */
%token <i_val> INT_LIT
%token <f_val> FLOAT_LIT
%token <s_val> STRING_LIT
%token <s_val> ID


/* Nonterminal with return, which need to sepcify type */
%type <i_val> primary_expression_1
%type <f_val> primary_expression_2
%type <s_val> primary_expression_3
%type <s_val> type_specifier

%left LOR
%left LAND
%left EQL NEQ
%left '<' '>' GEQ LEQ
%left LSHIFT RSHIFT
%left '%'
%left '+' '-'
%left '*' '/'
%right '!'


%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

/* Yacc will start at this nonterminal */
%start Program

/* Grammar section */
%%

Program
    : GlobalStatementList
;

GlobalStatementList 
    : GlobalStatementList GlobalStatement
    | GlobalStatement
;

GlobalStatement
    : FunctionDeclStmt blocks
    | NEWLINE
;

FunctionDeclStmt
    : function_head '(' parameter_list ')' 
    | function_head '(' parameter_list ')' arrow_head
;

function_head
    : FUNC ID
        { 
          address = -1;
          printf("func: %s\n" ,$2);
          insert_symbol($2, -1, -1, "func", "(V)V");
          strcpy(previous_func_name, $2);
          parameter_table = createQueue();
        }

arrow_head
    : ARROW type_specifier
        {
            change_func_sig_return(previous_func_name, tables[0], checktype);
        }
;
left_mark
    : '{'
        { 
            create_symbol(scope_level-1);
            if(getQsize(tables[scope_level-1]) > 0){
                insertMsg(tables[scope_level-1]);
            }
        }

;

right_mark
    : '}'
        { 
            scope_level--; 
            printTable(tables[scope_level], scope_level); 
            tables[scope_level] = NULL;
        }

;
blocks
    : left_mark statement_list right_mark
    | blocks left_mark statement_list right_mark
;

parameter_list 
    : /* empty */
    | parameter_list_nonempty
;

parameter_list_nonempty 
    : parameter_declaration
    | parameter_list_nonempty ',' parameter_declaration
;

parameter_declaration 
    : ID ':' type_specifier
    {
        SYMBOL* temp = new_symbol($3, getQsize(parameter_table), 0, checktype, address, yylineno + 1, "-", array_type);
        enqueue(parameter_table, temp);
        address++;
        change_func_sig(previous_func_name, tables[0], checktype);
    }
;

statement_list 
    : /* empty */
    | statement_list statement
;

statement
    : declaration ';'
    | assignment_statement ';'
    | conditional_statement
    | loop_statement
    | print_statement ';'
    | return_statement ';' 
    | break_statement ';'
    | empty_statement
    | function_call ';'
    | expression
        {
            printf("breturn\n");
        }
    | left_mark statement_list right_mark
;

function_call
    : ID '(' term_list  ')'
    {
        target = find_symbol_from_all($1);
        if(target != NULL){
            printf("call: %s%s\n" , target->name, target->func_sig);
        } else {
            printf("error\n");
        }
    }
;

empty_statement
    : NEWLINE
;

loop_statement 
    : WHILE expression blocks
    | for_loop statement_list right_mark
    | LOOP blocks
;

for_loop
    : FOR ID IN ID '{'
    {
        // printf("FOR %s IN %s\n", $2, $4);
        target = find_symbol_from_all($4);
        if(target != NULL){
            strcpy(print_type, target->type);
            printf("IDENT (name=%s, address=%d)\n" , yylval.s_val, target->address);
            printf("> Create symbol table (scope level %d)\n", scope_level-1);
            insert_symbol($2, address, 0, target->array_type, "-");
        } else {
            printf("error\n");
        }
    }
;


conditional_statement 
    : IF expression blocks %prec LOWER_THAN_ELSE
    | IF expression blocks ELSE blocks
;

print_statement 
    : PRINT expression
        { 
            printf("PRINT %s\n" ,print_type); is_print = true; 
        }
    | PRINTLN expression 
        { 
            printf("PRINTLN %s\n" ,print_type); is_print = true; 
        }
;

return_statement 
    : RETURN expression
        {
            printf("breturn\n");
        }
;

break_statement 
    : BREAK
    | BREAK expression
;

expression
    : primary_expression_1
    | primary_expression_2
    | '"' primary_expression_3 '"'
    | term
    | expression '+' expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "ADD");
            printf("ADD\n"); 
        }
    | expression '-' expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "SUB");
            printf("SUB\n"); 
        }
    | expression '*' expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "MUL");
            printf("MUL\n"); 
        }
    | expression '/' expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "DIV");
            printf("DIV\n"); 
        }
    | expression '%' expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "REM");
            printf("REM\n"); 
        }
    | expression LSHIFT expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "LSHIFT");
            printf("LSHIFT\n");
        }
    | expression RSHIFT expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "RSHIFT");
            printf("RSHIFT\n"); 
        }
    | expression '<' expression
        {   
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "LSS");
            printf("LSS\n"); 
        }
    | expression '>' expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "GTR");
            printf("GTR\n");
        }
    | expression LEQ expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "LEQ");
            printf("LEQ\n"); 
        }
    | expression GEQ expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "GEQ");
            printf("GEQ\n"); 
        }
    | expression EQL expression
        {   
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "EQL");
            printf("EQL\n"); 
        }
    | expression NEQ expression
        {   
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "NEQ");
            printf("NEQ\n"); 
        }
    | expression LAND expression
        {   
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "LAND");
            printf("LAND\n"); 
        }
    | expression LOR expression
        { 
            if(strcmp(first_type, second_type))
                invalid_oper_msg(yylineno+1, "LOR");
            printf("LOR\n"); 
        }
    | '!' expression %prec '-'
        {
            printf("NOT\n"); 
        }
    | '-' expression
        { 
            printf("NEG\n"); 
        }
    | '(' expression ')'
    | '[' expression ']'
    | function_call
    | TRUE
        { 
            printf("bool TRUE\n"); 
            strcpy(checktype, "bool"); 
            strcpy(print_type, "bool");
        }
    | FALSE
        { 
            printf("bool FALSE\n"); 
            strcpy(checktype, "bool"); 
            strcpy(print_type, "bool");
        }
;

primary_expression_1
    : INT_LIT
        { 
            $$ = $1; 
            printf("INT_LIT %d\n", $1); 
            strcpy(checktype, "i32"); 
            strcpy(print_type, "i32");
            if(round % 2 == 0){
                    strcpy(first_type, checktype);
            } else {
                    strcpy(second_type, checktype);
            }
            round++;
        }
    | INT_LIT AS type_specifier
        { 
            $$ = $1; 
            printf("INT_LIT %d\n", $1); 
            printf("i2f\n");
            if(round % 2 == 0){
                    strcpy(first_type, checktype);
            } else {
                    strcpy(second_type, checktype);
            }
            round++;
        }
    | primary_expression_1 ',' primary_expression_1
        { 
            $$ = $1; 
            strcpy(checktype, "array"); 
            strcpy(print_type, "array"); 
            strcpy(array_type, "i32");
        }
    | '[' primary_expression_1 ';' primary_expression_1 ']'
        { 
            strcpy(checktype, "array"); 
            strcpy(print_type, "array");
        }
;

primary_expression_2
    : FLOAT_LIT
        { 
            $$ = $1; 
            printf("FLOAT_LIT %f\n", $1); 
            strcpy(checktype, "f32"); 
            strcpy(print_type, "f32");
        }
    | FLOAT_LIT AS type_specifier
        { 
            $$ = $1; 
            printf("FLOAT_LIT %f\n", $1); 
            printf("f2i\n");
            if(round % 2 == 0){
                    strcpy(first_type, checktype);
            } else {
                    strcpy(second_type, checktype);
            }
            round++;
        }
    | primary_expression_2 ',' primary_expression_2
        { 
            $$ = $1; 
            strcpy(checktype, "array"); 
            strcpy(print_type, "array"); 
            strcpy(array_type, "f32");
        }
    | '[' primary_expression_2 ';' primary_expression_1 ']'
        { 
            strcpy(checktype, "array"); 
            strcpy(print_type, "array");
        }
;

primary_expression_3
    :  STRING_LIT 
        { 
            $$ = $1; 
            printf("STRING_LIT \"%s\"\n", $1); 
            strcpy(checktype, "str"); 
            strcpy(print_type, "str"); 
            strcpy(array_type, "str");
        }
    | /* empty */
        { 
            $$ = ""; 
            printf("STRING_LIT \"\"\n"); 
            strcpy(checktype, "str"); 
            strcpy(print_type, "str"); 
            strcpy(array_type, "str");
        }
;

term_list 
    : /* empty */
    | term_list_nonempty
;

term_list_nonempty
    : term
    | term_list_nonempty ',' term
;

term_ID
    : ID
        { 
            target = find_symbol_from_all(yylval.s_val);
            if(target != NULL){
                strcpy(print_type, target->type);
                printf("IDENT (name=%s, address=%d)\n" , yylval.s_val, target->address);
                if(round % 2 == 0){
                    strcpy(first_type, target->type);
                } else {
                    strcpy(second_type, target->type);
                }
                
            } else {
                is_print = false;
                undefined_msg(yylineno + 1, $1);
                if(round % 2 == 0){
                    strcpy(first_type, "undefined");
                } else {
                    strcpy(second_type, "undefined");
                }
            }
            round++;
        }
;

term_DOTDOT
    : DOTDOT
        { 
            printf("DOTDOT\n");
        }
;

term
    : term_ID
    | ID AS type_specifier
        {
            target = find_symbol_from_all(yylval.s_val);
            if(target != NULL){
                strcpy(print_type, target->type);
                printf("IDENT (name=%s, address=%d)\n" , yylval.s_val, target->address);
                if(strcmp(target->type, "i32") == 0 && strcmp(checktype, "f32") == 0)
                {
                    printf("i2f\n");
                    if(round % 2 == 0){
                        strcpy(first_type, "f32");
                    } else {
                        strcpy(second_type, "f32");
                    }
                } 
                else if(strcmp(target->type, "i32") == 0 && strcmp(checktype, "i32") == 0) 
                {
                    printf("i2i\n");
                    if(round % 2 == 0){
                        strcpy(first_type, "i32");
                    } else {
                        strcpy(second_type, "i32");
                    }
                } 
                else if((strcmp(target->type, "f32") == 0 && strcmp(checktype, "i32") == 0))
                {
                    printf("f2i\n");
                    if(round % 2 == 0){
                        strcpy(first_type, "i32");
                    } else {
                        strcpy(second_type, "i32");
                    }
                } 
                else if((strcmp(target->type, "f32") == 0 && strcmp(checktype, "f32") == 0)){
                    printf("f2f\n");
                    if(round % 2 == 0){
                        strcpy(first_type, "f32");
                    } else {
                        strcpy(second_type, "f32");
                    }
                }
                round++;

            } else {
                printf("error\n");
            }

            
        }
    | array_term
    | '&' term_ID '[' primary_expression_1 term_DOTDOT ']'
        { 
            strcpy(checktype, "str"); strcpy(print_type, "str"); strcpy(array_type, "str");
        }
    | '&' term_ID'[' primary_expression_1 term_DOTDOT primary_expression_1']'
        { 
            strcpy(checktype, "str"); strcpy(print_type, "str"); strcpy(array_type, "str");
        }
    | '&' term_ID '[' term_DOTDOT primary_expression_1']'
        { 
            strcpy(checktype, "str"); strcpy(print_type, "str"); strcpy(array_type, "str");
        } 
;

array_term
    : ID '[' INT_LIT ']'
        { 
            target = find_symbol_from_all($1);
            if(target != NULL){
                strcpy(print_type, target->type);
                printf("IDENT (name=%s, address=%d)\n" , $1, target->address);
                if(round % 2 == 0){
                    strcpy(first_type, target->type);
                } else {
                    strcpy(second_type, target->type);
                }
                
            } else {
                is_print = false;
                undefined_msg(yylineno + 1, $1);
                if(round % 2 == 0){
                    strcpy(first_type, "undefined");
                } else {
                    strcpy(second_type, "undefined");
                }
            }
            printf("INT_LIT %d\n", $3); 
            strcpy(checktype, "array"); 
            strcpy(print_type, "array");
        }
    | ID '[' INT_LIT ']' '[' INT_LIT ']'
        { 
            printf("INT_LIT %d\n", $3);
            printf("INT_LIT %d\n", $6);
            strcpy(checktype, "array"); 
            strcpy(print_type, "array"); 
        }

;

type_specifier
    : INT
        { 
            strcpy(checktype, "i32");
        }
    | FLOAT
        { 
            strcpy(checktype, "f32");
        }
    | BOOL
        { 
            strcpy(checktype, "bool");
        }
    | '&' STR
        { 
            strcpy(checktype, "str");
        }
    | '[' type_specifier ';' primary_expression_1 ']'
        { strcpy(checktype, "array");}
;

declaration
    : LET ID ':' type_specifier '=' expression
        { 
            insert_symbol($2, address, 0, checktype, "-");
        }
    | LET ID ':' type_specifier '=' loop_statement
        { 
            insert_symbol($2, address, 0, checktype, "-");
        }
    | LET MUT ID ':' type_specifier '=' expression
        { 
            insert_symbol($3, address, 1, checktype, "-");
        }
    | LET ID ':' type_specifier
        { 
            insert_symbol($2, address, 0, checktype, "-");
        }
    | LET MUT ID ':' type_specifier
        { 
            insert_symbol($3, address, 1, checktype, "-");
        }
    | LET ID '=' expression
        { 
            insert_symbol($2, address, 0, checktype, "-");
        }
    | LET MUT ID '=' expression
        { 
            insert_symbol($3, address, 1, checktype, "-");
        }
;


assignment_statement 
    : ID '=' expression
        {           
            target = find_symbol_from_all($1);
            if(target != NULL){
                printf("ASSIGN\n");
            } else {
                undefined_msg(yylineno + 1, $1);
            }
        }
    | ID ADD_ASSIGN expression
        { 
            printf("ADD_ASSIGN\n"); 
        }
    | ID SUB_ASSIGN expression
        { 
            printf("SUB_ASSIGN\n"); 
        }
    | ID MUL_ASSIGN expression
        { 
            printf("MUL_ASSIGN\n"); 
        }
    | ID DIV_ASSIGN expression
        { 
            printf("DIV_ASSIGN\n"); 
        }
    | ID REM_ASSIGN expression
        { 
            printf("REM_ASSIGN\n"); 
        }
    | array_term '=' expression
    | array_term ADD_ASSIGN expression
    | array_term SUB_ASSIGN expression
    | array_term MUL_ASSIGN expression
    | array_term DIV_ASSIGN expression
    | array_term REM_ASSIGN expression
;

%%

/* C code section */
int main(int argc, char *argv[])
{
    if (argc == 2) {
        yyin = fopen(argv[1], "r");
    } else {
        yyin = stdin;
    }
    yylineno = 0;
    create_symbol(0);
    tables[0] = createQueue();
    yyparse();

    dump_symbol();
	printf("Total lines: %d\n", yylineno);

    /* printTable(parameter_table, 0); */
    fclose(yyin);
    return 0;
}

static void create_symbol(int index) {
    /* printf("> Create symbol table (scope level %d)\n", 0); */
    printf("> Create symbol table (scope level %d)\n", index);
}

static void insert_symbol(char *name, int addr, int mut, char *type, char *func_sig) {
    /* printf("> Insert `%s` (addr: %d) to scope level %d\n", "XXX", 0, 0); */
    printf("> Insert `%s` (addr: %d) to scope level %d\n", name, addr, scope_level-1);
    SYMBOL* temp = new_symbol(name, getQsize(tables[scope_level-1]), mut, type, addr, yylineno + 1, func_sig, array_type);
    enqueue(tables[scope_level-1], temp);
    address++;
}

static void lookup_symbol() {
}

static void dump_symbol() {
    /* printf("\n> Dump symbol table (scope level: %d)\n", 0);
    printf("%-10s%-10s%-10s%-10s%-10s%-10s%-10s\n",
        "Index", "Name", "Mut","Type", "Addr", "Lineno", "Func_sig");
    printf("%-10d%-10s%-10d%-10s%-10d%-10d%-10s\n",
            0, "name", 0, "type", 0, 0, "func_sig"); */
    printTable(tables[0], 0);
}

static void invalid_oper_msg(int lines, char* op)
{
    if(round % 2 == 0)
        printf("error:%d: invalid operation: %s (mismatched types %s and %s)\n", lines, op, first_type, second_type);
    else
        printf("error:%d: invalid operation: %s (mismatched types %s and %s)\n", lines, op, second_type, first_type);
}

static void undefined_msg(int lines, char* name)
{
    printf("error:%d: undefined: %s\n", lines, name);
}
```