%{ #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) { .type = ARG_INTEGER, .value = (v) } #define MKARGLABEL(l) (struct argument) { .type = ARG_LABEL, .label = (l) } #define MKARGTYPE(t) (struct argument) { .type = (t) } #define MKARGEXPR(op,...) (struct argument) { .type = (op), .children = { __VA_ARGS__ } } %} %output "parser.c" %defines "parser.h" %code requires { #include "nqasm.h" } %union { struct instruction inst; struct arguments args; struct argument arg; long lval; char *str; } %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_LABEL %token T_INT %token T_BADINT %token T_COMMA "," %token T_COLON ":" %token T_DOT "." %token T_DEREF "@" %token T_OPERATOR_ADD "+" %token T_OPERATOR_SUB "-" %token T_OPERATOR_MUL "*" %token T_OPERATOR_DIV "/" %token T_OPERATOR_NOT "!" %token T_OPERATOR_INV "~" %token T_LPAREN "(" %token T_RPAREN ")" %left "-" "+" %left "*" "/" %precedence NEG %type inst %type reg %type regp %type expr %type a_reg2 %type a_reg3 %type a_regp %type a_regp_reg %type a_reg_regp %type a_reg_expr %type a_expr %type intlit %% input: line | input line ; line: bol inst eol { add_instruction(&$2); } | eol ; bol: T_SPACE | T_LABEL ":" { add_label($1); } ; 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_expr { $$ = INSTRUCTION_ARGS(LDI_BL, $2); } | T_LDI_BH a_reg_expr { $$ = INSTRUCTION_ARGS(LDI_BH, $2); } | T_BEQ a_expr { $$ = INSTRUCTION_ARGS(BEQ, $2); } | T_BNE a_expr { $$ = INSTRUCTION_ARGS(BNE, $2); } | T_BGT a_expr { $$ = INSTRUCTION_ARGS(BGT, $2); } | T_BGE a_expr { $$ = INSTRUCTION_ARGS(BGE, $2); } | T_BLT a_expr { $$ = INSTRUCTION_ARGS(BLT, $2); } | T_BLE a_expr { $$ = INSTRUCTION_ARGS(BLE, $2); } | T_BRA a_expr { $$ = INSTRUCTION_ARGS(BRA, $2); } | T_JMP a_regp { $$ = INSTRUCTION_ARGS(JMP, $2); } | T_ADDPC a_reg_expr { $$ = INSTRUCTION_ARGS(ADDPC, $2); } | T_NOP { $$ = INSTRUCTION(NOP); } ; a_reg2: T_SPACE reg "," reg { $$ = MKARGS($2, $4); } a_reg3: T_SPACE reg "," reg "," reg { $$ = MKARGS($2, $4, $6); } a_regp: T_SPACE regp { $$ = MKARGS($2); } a_regp_reg: T_SPACE regp "," reg { $$ = MKARGS($2, $4); } a_reg_regp: T_SPACE reg "," regp { $$ = MKARGS($2, $4); } a_reg_expr: T_SPACE reg "," expr { $$ = MKARGS($2, $4); } a_expr: T_SPACE expr { $$ = MKARGS($2); } regp: "@" reg { $$ = $2; } reg: T_LABEL { int bad = 0; if ($1[0] != 'r' && $1[0] != 'R') bad = 1; else if (0 > $1[1] - '0' || $1[1] - '0' > 9) bad = 1; else if ($1[2]) bad = 1; if (bad) { yyerror("invalid register"); YYERROR; } else { $$ = MKARGVALUE($1[1] - '0'); } } expr: intlit { $$ = MKARGVALUE($1); } | T_LABEL { $$ = MKARGLABEL($1); } | "." { $$ = MKARGTYPE(ARG_PC); } | "+" expr %prec NEG { $$ = MKARGEXPR(ARG_UNARY_ADD, argdup(&$2)); } | "-" expr %prec NEG { $$ = MKARGEXPR(ARG_UNARY_SUB, argdup(&$2)); } | "!" expr %prec NEG { $$ = MKARGEXPR(ARG_UNARY_NOT, argdup(&$2)); } | "~" expr %prec NEG { $$ = MKARGEXPR(ARG_UNARY_INV, argdup(&$2)); } | expr "+" expr { $$ = MKARGEXPR(ARG_ADD, argdup(&$1), argdup(&$3)); } | expr "-" expr { $$ = MKARGEXPR(ARG_SUB, argdup(&$1), argdup(&$3)); } | expr "*" expr { $$ = MKARGEXPR(ARG_MUL, argdup(&$1), argdup(&$3)); } | expr "/" expr { $$ = MKARGEXPR(ARG_DIV, argdup(&$1), argdup(&$3)); } | "(" expr ")" { $$ = $2; } ; intlit: T_INT | T_BADINT { yyerror("integer literal out of range"); YYERROR; } eol: T_EOL | T_SPACE T_EOL ;