%{ #include #include "lexer.h" #include "mnemonics.h" void yyerror(const char *msg) { fprintf(stderr, "%s\n", msg); } #define INSTRUCTION_ARGS(m,a) (struct instruction) { MNEM_ ## m, a } #define INSTRUCTION(m) (struct instruction) { MNEM_ ## m } #define MKARGS(...) (struct arguments) { __VA_ARGS__ } #define MKARGVALUE(v) (struct argument) { (v) } %} %output "parser.c" %defines "parser.h" %code requires { #include "nqasm.h" } %union { struct instruction inst; struct arguments args; struct argument arg; long lval; } %token END 0 "end of file" %token T_SPACE %token T_EOL %token T_ADD %token T_SUB %token T_MUL %token T_DIV %token T_AND %token T_OR %token T_XOR %token T_LSL %token T_LSR %token T_ASL %token T_ASR %token T_ROL %token T_ROR %token T_NOT %token T_NEG %token T_BTC %token T_BTS %token T_MOV %token T_ST_B %token T_ST_W %token T_LD_BL %token T_LD_BH %token T_LD_W %token T_LDI_BL %token T_LDI_BH %token T_BEQ %token T_BNE %token T_BGT %token T_BGE %token T_BLT %token T_BLE %token T_BRA %token T_JMP %token T_ADDPC %token T_NOP %token T_INT %token T_BADINT %token T_REG %token T_REGPTR %token T_COMMA "," %type inst %type imm %type pcoff %type a_reg2 %type a_reg3 %type a_regp %type a_regp_reg %type a_reg_regp %type a_reg_imm %type a_reg_pcoff %type a_pcoff %type intlit %% input: line | input line ; line: T_SPACE inst eol { add_instruction(&$2); } | eol ; inst: T_ADD a_reg3 { $$ = INSTRUCTION_ARGS(ADD, $2); } | T_SUB a_reg3 { $$ = INSTRUCTION_ARGS(SUB, $2); } | T_MUL a_reg3 { $$ = INSTRUCTION_ARGS(MUL, $2); } | T_DIV a_reg3 { $$ = INSTRUCTION_ARGS(DIV, $2); } | T_AND a_reg3 { $$ = INSTRUCTION_ARGS(AND, $2); } | T_OR a_reg3 { $$ = INSTRUCTION_ARGS(OR, $2); } | T_XOR a_reg3 { $$ = INSTRUCTION_ARGS(XOR, $2); } | T_LSL a_reg3 { $$ = INSTRUCTION_ARGS(LSL, $2); } | T_LSR a_reg3 { $$ = INSTRUCTION_ARGS(LSR, $2); } | T_ASL a_reg3 { $$ = INSTRUCTION_ARGS(ASL, $2); } | T_ASR a_reg3 { $$ = INSTRUCTION_ARGS(ASR, $2); } | T_ROL a_reg3 { $$ = INSTRUCTION_ARGS(ROL, $2); } | T_ROR a_reg3 { $$ = INSTRUCTION_ARGS(ROR, $2); } | T_NOT a_reg2 { $$ = INSTRUCTION_ARGS(NOT, $2); } | T_NEG a_reg2 { $$ = INSTRUCTION_ARGS(NEG, $2); } | T_BTC a_reg2 { $$ = INSTRUCTION_ARGS(BTC, $2); } | T_BTS a_reg2 { $$ = INSTRUCTION_ARGS(BTS, $2); } | T_MOV a_reg2 { $$ = INSTRUCTION_ARGS(MOV, $2); } | T_ST_B a_regp_reg { $$ = INSTRUCTION_ARGS(ST_B, $2); } | T_ST_W a_regp_reg { $$ = INSTRUCTION_ARGS(ST_W, $2); } | T_LD_BL a_reg_regp { $$ = INSTRUCTION_ARGS(LD_BL, $2); } | T_LD_BH a_reg_regp { $$ = INSTRUCTION_ARGS(LD_BH, $2); } | T_LD_W a_reg_regp { $$ = INSTRUCTION_ARGS(LD_W, $2); } | T_LDI_BL a_reg_imm { $$ = INSTRUCTION_ARGS(LDI_BL, $2); } | T_LDI_BH a_reg_imm { $$ = INSTRUCTION_ARGS(LDI_BH, $2); } | T_BEQ a_pcoff { $$ = INSTRUCTION_ARGS(BEQ, $2); } | T_BNE a_pcoff { $$ = INSTRUCTION_ARGS(BNE, $2); } | T_BGT a_pcoff { $$ = INSTRUCTION_ARGS(BGT, $2); } | T_BGE a_pcoff { $$ = INSTRUCTION_ARGS(BGE, $2); } | T_BLT a_pcoff { $$ = INSTRUCTION_ARGS(BLT, $2); } | T_BLE a_pcoff { $$ = INSTRUCTION_ARGS(BLE, $2); } | T_BRA a_pcoff { $$ = INSTRUCTION_ARGS(BRA, $2); } | T_JMP a_regp { $$ = INSTRUCTION_ARGS(JMP, $2); } | T_ADDPC a_reg_pcoff { $$ = INSTRUCTION_ARGS(ADDPC, $2); } | T_NOP { $$ = INSTRUCTION(NOP); } ; a_reg2: T_SPACE T_REG "," T_REG { $$ = MKARGS($2, $4); } a_reg3: T_SPACE T_REG "," T_REG "," T_REG { $$ = MKARGS($2, $4, $6); } a_regp: T_SPACE T_REGPTR { $$ = MKARGS($2); } a_regp_reg: T_SPACE T_REGPTR "," T_REG { $$ = MKARGS($2, $4); } a_reg_regp: T_SPACE T_REG "," T_REGPTR { $$ = MKARGS($2, $4); } a_reg_imm: T_SPACE T_REG "," imm { $$ = MKARGS($2, $4); } a_reg_pcoff: T_SPACE T_REG "," pcoff { $$ = MKARGS($2, $4); } a_pcoff: T_SPACE pcoff { $$ = MKARGS($2); } pcoff: intlit { if (-0x80 > $1 || $1 > 0x7f) { yyerror("pc offset operand out of range"); YYERROR; } else { $$ = MKARGVALUE((uint8_t) $1); } } imm: intlit { if (-0x80 > $1 || $1 > 0xff) { yyerror("immediate operand out of range"); YYERROR; } else { $$ = MKARGVALUE((uint8_t) $1); } } intlit: T_INT | T_BADINT { yyerror("integer literal out of range"); YYERROR; } eol: T_EOL | T_SPACE T_EOL ;