summaryrefslogtreecommitdiff
path: root/parser.y
blob: ed33aa4eb646b2cc5615d7296552100962b67bdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
%{

#include <stdio.h>

#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 <str>  T_LABEL
%token <lval> 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> inst
%type <arg>  reg
%type <arg>  regp
%type <arg>  expr
%type <args> a_reg2
%type <args> a_reg3
%type <args> a_regp
%type <args> a_regp_reg
%type <args> a_reg_regp
%type <args> a_reg_expr
%type <args> a_expr
%type <lval> 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
	;