📄 parser.y
字号:
fatal_error ("File contains an .err directive\n"); } | Y_FILE_DIR Y_INT Y_STR | Y_FLOAT_DIR { store_op = store_float; if (data_dir) set_data_alignment (2); } FP_EXPR_LST { if (text_dir) yyerror ("Can't put data in text segment"); } | Y_FMASK_DIR Y_INT Y_INT | Y_FRAME_DIR REGISTER Y_INT REGISTER | Y_GLOBAL_DIR ID { (void)make_label_global ((char*)$2.p); free ((char*)$2.p); } | Y_HALF_DIR { store_op = store_half; if (data_dir) set_data_alignment (1); } EXPR_LST { if (text_dir) yyerror ("Can't put data in text segment"); } | Y_LABEL_DIR ID { (void)record_label ((char*)$2.p, text_dir ? current_text_pc () : current_data_pc (), 1); free ((char*)$2.p); } | Y_LCOMM_DIR ID EXPR { lcomm_directive ((char*)$2.p, $3.i); } /* Produced by cc 2.10 */ | Y_LIVEREG_DIR Y_INT Y_INT | Y_LOC_DIR Y_INT Y_INT | Y_MASK_DIR Y_INT Y_INT | Y_NOALIAS_DIR Y_REG Y_REG | Y_OPTIONS_DIR ID | Y_REPEAT_DIR EXPR { yyerror ("Warning: repeat directive ignored"); } | Y_RDATA_DIR { user_kernel_data_segment (0); data_dir = 1; text_dir = 0; enable_data_alignment (); } | Y_RDATA_DIR Y_INT { user_kernel_data_segment (0); data_dir = 1; text_dir = 0; enable_data_alignment (); set_data_pc ($2.i); } | Y_SDATA_DIR { user_kernel_data_segment (0); data_dir = 1; text_dir = 0; enable_data_alignment (); } | Y_SDATA_DIR Y_INT { user_kernel_data_segment (0); data_dir = 1; text_dir = 0; enable_data_alignment (); set_data_pc ($2.i); } | Y_SET_DIR ID { if (streq ((char*)$2.p, "noat")) noat_flag = 1; else if (streq ((char*)$2.p, "at")) noat_flag = 0; } | Y_SPACE_DIR EXPR { if (data_dir) increment_data_pc ($2.i); else if (text_dir) increment_text_pc ($2.i); } | Y_STRUCT_DIR EXPR { yyerror ("Warning: struct directive ignored"); } | Y_TEXT_DIR { user_kernel_text_segment (0); data_dir = 0; text_dir = 1; enable_data_alignment (); } | Y_TEXT_DIR Y_INT { user_kernel_text_segment (0); data_dir = 0; text_dir = 1; enable_data_alignment (); set_text_pc ($2.i); } | Y_K_TEXT_DIR { user_kernel_text_segment (1); data_dir = 0; text_dir = 1; enable_data_alignment (); } | Y_K_TEXT_DIR Y_INT { user_kernel_text_segment (1); data_dir = 0; text_dir = 1; enable_data_alignment (); set_text_pc ($2.i); } | Y_VERSTAMP_DIR Y_INT Y_INT | Y_VREG_DIR REGISTER Y_INT Y_INT | Y_WORD_DIR { store_op = store_word_data; if (data_dir) set_data_alignment (2); } EXPR_LST ;ADDRESS: {only_id = 1;} ADDR {only_id = 0; $$ = $2;}ADDR: '(' REGISTER ')' { $$.p = make_addr_expr (0, NULL, $2.i); } | ABS_ADDR { $$.p = make_addr_expr ($1.i, NULL, 0); } | ABS_ADDR '(' REGISTER ')' { $$.p = make_addr_expr ($1.i, NULL, $3.i); } | Y_ID { $$.p = make_addr_expr (0, (char*)$1.p, 0); free ((char*)$1.p); } | Y_ID '(' REGISTER ')' { $$.p = make_addr_expr (0, (char*)$1.p, $3.i); free ((char*)$1.p); } | Y_ID '+' ABS_ADDR { $$.p = make_addr_expr ($3.i, (char*)$1.p, 0); free ((char*)$1.p); } | ABS_ADDR '+' ID { $$.p = make_addr_expr ($1.i, (char*)$3.p, 0); } | Y_ID '-' ABS_ADDR { $$.p = make_addr_expr (- $3.i, (char*)$1.p, 0); free ((char*)$1.p); } | Y_ID '+' ABS_ADDR '(' REGISTER ')' { $$.p = make_addr_expr ($3.i, (char*)$1.p, $5.i); free ((char*)$1.p); } | Y_ID '-' ABS_ADDR '(' REGISTER ')' { $$.p = make_addr_expr (- $3.i, (char*)$1.p, $5.i); free ((char*)$1.p); } ;BR_IMM32: {only_id = 1;} IMM32 {only_id = 0; $$ = $2;}IMM16: IMM32 { check_imm_range ($1.p, IMM_MIN, IMM_MAX); $$ = $1; }UIMM16: IMM32 { check_uimm_range ($1.p, UIMM_MIN, UIMM_MAX); $$ = $1; }IMM32: ABS_ADDR { $$.p = make_imm_expr ($1.i, NULL, 0); } | '(' ABS_ADDR ')' '>' '>' Y_INT { $$.p = make_imm_expr ($2.i >> $6.i, NULL, 0); } | ID { $$.p = make_imm_expr (0, (char*)$1.p, 0); } | Y_ID '+' ABS_ADDR { $$.p = make_imm_expr ($3.i, (char*)$1.p, 0); free ((char*)$1.p); } | Y_ID '-' ABS_ADDR { $$.p = make_imm_expr (- $3.i, (char*)$1.p, 0); free ((char*)$1.p); } ;ABS_ADDR: Y_INT | Y_INT '+' Y_INT {$$.i = $1.i + $3.i;} | Y_INT Y_INT { /* This is actually: Y_INT '-' Y_INT, since the binary subtract operator gets scanned as a unary negation operator. */ if ($2.i >= 0) yyerror ("Syntax error"); $$.i = $1.i - -$2.i; } ;SRC1: REGISTER ;SRC2: REGISTER ;DEST: REGISTER ;REG: REGISTER ;REGISTER: Y_REG { if ($1.i < 0 || $1.i > 31) yyerror ("Register number out of range"); if ($1.i == 1 && !bare_machine && !noat_flag) yyerror ("Register 1 is reserved for assembler"); $$ = $1; }F_DEST: FP_REGISTER ;F_SRC1: FP_REGISTER ;F_SRC2: FP_REGISTER ;FP_REGISTER: Y_FP_REG { if ($1.i < 0 || $1.i > 31) yyerror ("FP register number out of range"); $$ = $1; }CC_REG: Y_INT { if ($1.i < 0 || $1.i > 7) yyerror ("CC register number out of range"); $$ = $1; }COP_REG: Y_REG | Y_FP_REG ;LABEL: ID { $$.p = make_imm_expr (-(int)current_text_pc (), (char*)$1.p, 1); }STR_LST: STR_LST STR | STR ;STR: Y_STR { store_string ((char*)$1.p, strlen((char*)$1.p), null_term); free ((char*)$1.p); } | Y_STR ':' Y_INT { int i; for (i = 0; i < $3.i; i ++) store_string ((char*)$1.p, strlen((char*)$1.p), null_term); free ((char*)$1.p); } ;EXPRESSION: {only_id = 1;} EXPR {only_id = 0; $$ = $2;}EXPR: Y_INT | ID { label *l = lookup_label ((char*)$1.p); if (l->addr == 0) { record_data_uses_symbol (current_data_pc (), l); $$.p = NULL; } else $$.i = l->addr; }EXPR_LST: EXPR_LST EXPRESSION { store_op ($2.p); } | EXPRESSION { store_op ($1.p); } | EXPRESSION ':' Y_INT { int i; for (i = 0; i < $3.i; i ++) store_op ($1.p); } ;FP_EXPR_LST: FP_EXPR_LST Y_FP { store_op ($2.p); } | Y_FP { store_op ($1.p); } ;OPTIONAL_ID: {only_id = 1;} OPT_ID {only_id = 0; $$ = $2;}OPT_ID: ID | {$$.p = (void*)NULL;} ;ID: {only_id = 1;} Y_ID {only_id = 0; $$ = $2;}%%/* Maintain and update the address of labels for the current line. */voidfix_current_label_address (mem_addr new_addr){ label_list *l; for (l = this_line_labels; l != NULL; l = l->tail) { l->head->addr = new_addr; } clear_labels ();}static label_list *cons_label (label *head, label_list *tail){ label_list *c = (label_list *) malloc (sizeof (label_list)); c->head = head; c->tail = tail; return (c);}static voidclear_labels (){ label_list *n; for ( ; this_line_labels != NULL; this_line_labels = n) { resolve_label_uses (this_line_labels->head); n = this_line_labels->tail; free (this_line_labels); } this_line_labels = NULL;}/* Operations on op codes. */intop_to_imm_op (int opcode){ switch (opcode) { case Y_ADD_OP: return (Y_ADDI_OP); case Y_ADDU_OP: return (Y_ADDIU_OP); case Y_AND_OP: return (Y_ANDI_OP); case Y_OR_OP: return (Y_ORI_OP); case Y_XOR_OP: return (Y_XORI_OP); case Y_SLT_OP: return (Y_SLTI_OP); case Y_SLTU_OP: return (Y_SLTIU_OP); case Y_SLLV_OP: return (Y_SLL_OP); case Y_SRAV_OP: return (Y_SRA_OP); case Y_SRLV_OP: return (Y_SRL_OP); default: fatal_error ("Can't convert op to immediate op\n"); return (0); }}intimm_op_to_op (int opcode){ switch (opcode) { case Y_ADDI_OP: return (Y_ADD_OP); case Y_ADDIU_OP: return (Y_ADDU_OP); case Y_ANDI_OP: return (Y_AND_OP); case Y_ORI_OP: return (Y_OR_OP); case Y_XORI_OP: return (Y_XOR_OP); case Y_SLTI_OP: return (Y_SLT_OP); case Y_SLTIU_OP: return (Y_SLTU_OP); case Y_J_OP: return (Y_JR_OP); case Y_LUI_OP: return (Y_ADDU_OP); case Y_SLL_OP: return (Y_SLLV_OP); case Y_SRA_OP: return (Y_SRAV_OP); case Y_SRL_OP: return (Y_SRLV_OP); default: fatal_error ("Can't convert immediate op to op\n"); return (0); }}static voidnop_inst (){ r_type_inst (Y_SLL_OP, 0, 0, 0); /* = 0 */}static voidtrap_inst (){ r_type_inst (Y_BREAK_OP, 0, 0, 0);}static imm_expr *branch_offset (int n_inst){ return (const_imm_expr (n_inst << 2)); /* Later shifted right 2 places */}static voiddiv_inst (int op, int rd, int rs, int rt, int const_divisor){ if (rd != 0 && !const_divisor) { i_type_inst_free (Y_BNE_OP, 0, rt, branch_offset (2)); trap_inst (); } if (op == Y_DIV_OP || op == Y_REM_POP) r_type_inst (Y_DIV_OP, 0, rs, rt); else r_type_inst (Y_DIVU_OP, 0, rs, rt); if (rd != 0) { if (op == Y_DIV_OP || op == Y_DIVU_OP) /* Quotient */ r_type_inst (Y_MFLO_OP, rd, 0, 0); else /* Remainder */ r_type_inst (Y_MFHI_OP, rd, 0, 0); }}static voidmult_inst (int op, int rd, int rs, int rt){ if (op == Y_MULOU_POP) r_type_inst (Y_MULTU_OP, 0, rs, rt); else r_type_inst (Y_MULT_OP, 0, rs, rt); if (op == Y_MULOU_POP && rd != 0) { r_type_inst (Y_MFHI_OP, 1, 0, 0); /* Use $at */ i_type_inst_free (Y_BEQ_OP, 0, 1, branch_offset (2)); trap_inst (); } else if (op == Y_MULO_POP && rd != 0) { r_type_inst (Y_MFHI_OP, 1, 0, 0); /* use $at */ r_type_inst (Y_MFLO_OP, rd, 0, 0); r_sh_type_inst (Y_SRA_OP, rd, rd, 31); i_type_inst_free (Y_BEQ_OP, rd, 1, branch_offset (2)); trap_inst (); } if (rd != 0) r_type_inst (Y_MFLO_OP, rd, 0, 0);}static voidset_le_inst (int op, int rd, int rs, int rt){ i_type_inst_free (Y_BNE_OP, rs, rt, branch_offset (3)); i_type_inst_free (Y_ORI_OP, rd, 0, const_imm_expr (1)); i_type_inst_free (Y_BEQ_OP, 0, 0, branch_offset (2)); r_type_inst ((op == Y_SLE_POP ? Y_SLT_OP : Y_SLTU_OP), rd, rs, rt);}static voidset_gt_inst (int op, int rd, int rs, int rt){ r_type_inst (op == Y_SGT_POP ? Y_SLT_OP : Y_SLTU_OP, rd, rt, rs);}static voidset_ge_inst (int op, int rd, int rs, int rt){ i_type_inst_free (Y_BNE_OP, rs, rt, branch_offset (3)); i_type_inst_free (Y_ORI_OP, rd, 0, const_imm_expr (1)); i_type_inst_free (Y_BEQ_OP, 0, 0, branch_offset (2)); r_type_inst (op == Y_SGE_POP ? Y_SLT_OP : Y_SLTU_OP, rd, rt, rs);}static voidset_eq_inst (int op, int rd, int rs, int rt){ imm_expr *if_eq, *if_neq; if (op == Y_SEQ_POP) if_eq = const_imm_expr (1), if_neq = const_imm_expr (0); else if_eq = const_imm_expr (0), if_neq = const_imm_expr (1); i_type_inst_free (Y_BEQ_OP, rs, rt, branch_offset (3)); /* RD <- 0 (if not equal) */ i_type_inst_free (Y_ORI_OP, rd, 0, if_neq); i_type_inst_free (Y_BEQ_OP, 0, 0, branch_offset (2)); /* Branch always */ /* RD <- 1 */ i_type_inst_free (Y_ORI_OP, rd, 0, if_eq);}/* Store the value either as a datum or instruction. */static voidstore_word_data (int value){ if (data_dir) store_word (value); else if (text_dir) store_instruction (inst_decode (value));}voidinitialize_parser (char *file_name){ input_file_name = file_name; only_id = 0; data_dir = 0; text_dir = 1;}static voidcheck_imm_range (imm_expr* expr, int32 min, int32 max){ if (expr->symbol == NULL || SYMBOL_IS_DEFINED (expr->symbol)) { /* If expression can be evaluated, compare its value against the limits and complain if the value is out of bounds. */ int32 value = eval_imm_expr (expr); if (value < min || max < value) { char str[200]; sprintf (str, "immediate value (%d) out of range (%d .. %d)", value, min, max); yywarn (str); } }}static voidcheck_uimm_range (imm_expr* expr, uint32 min, uint32 max){ if (expr->symbol == NULL || SYMBOL_IS_DEFINED (expr->symbol)) { /* If expression can be evaluated, compare its value against the limits and complain if the value is out of bounds. */ uint32 value = (uint32)eval_imm_expr (expr); if (value < min || max < value) { char str[200]; sprintf (str, "immediate value (%d) out of range (%d .. %d)", (int32)value, (int32)min, (int32)max); yywarn (str); } }}voidyyerror (char *s){ parse_error_occurred = 1; clear_labels (); yywarn (s);}voidyywarn (char *s){ error ("spim: (parser) %s on line %d of file %s\n", s, line_no, input_file_name); print_erroneous_line ();}static voidmips32_r2_inst (){ yyerror ("Warning: MIPS32 Rev 2 instruction is not implemented. Instruction ignored.");}static intcc_to_rt (int cc, int nd, int tf){ return (cc << 2) | (nd << 1) | tf;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -