kulp / tenyr
1
%{
2
#include <stdio.h>
3
#include <ctype.h>
4
#include <stdint.h>
5
#include <string.h>
6
#include <stdlib.h>
7
#include <stdarg.h>
8
#include <assert.h>
9

10
#include "common.h"
11
#include "parser_global.h"
12
#include "expr.h"
13
#include "parser.h"
14
#define YY_HEADER_EXPORT_START_CONDITIONS 1
15
#include "lexer.h"
16
#include "asm.h"
17

18
int tenyr_error(YYLTYPE *locp, struct parse_data *pd, const char *fmt, ...);
19
static struct const_expr *add_deferred_expr(struct parse_data *pd,
20
        struct const_expr *ce, int mult, int32_t *dest, int width, int flags);
21
static struct const_expr *make_expr(struct parse_data *pd, YYLTYPE *locp,
22
        enum const_expr_type type, int op, struct const_expr *left,
23
        struct const_expr *right, int flags);
24
static struct const_expr *make_imm(struct parse_data *pd, YYLTYPE *locp,
25
        int val, int flags);
26
static struct expr *make_rhs(int type, int x, int op, int y, int mult,
27
        struct const_expr *defexpr);
28
static struct expr *make_unary(int op, int x, int y, int mult,
29
        struct const_expr *defexpr);
30
static struct element *make_insn_general(struct parse_data *pd,
31
        struct expr *lhs, int arrow, struct expr *expr);
32
static struct element_list *make_chars(struct cstr *cs);
33
static int add_symbol_to_insn(struct parse_data *pd, YYLTYPE *locp,
34
        struct element *insn, struct cstr *symbol);
35
static struct element_list *make_data(struct parse_data *pd,
36
        struct const_expr_list *list);
37
static struct element_list *make_zeros(struct parse_data *pd, YYLTYPE *locp,
38
        struct const_expr *size);
39
static struct directive *make_global(struct parse_data *pd, YYLTYPE *locp,
40
        const struct cstr *sym);
41
static struct directive *make_set(struct parse_data *pd, YYLTYPE *locp,
42
        const struct cstr *sym, struct const_expr *expr);
43
static void handle_directive(struct parse_data *pd, YYLTYPE *locp,
44
        struct directive *d, struct element_list **context);
45
static struct const_expr *make_ref(struct parse_data *pd, YYLTYPE *locp,
46
        enum const_expr_type type, const struct cstr *symbol);
47
static struct const_expr *make_eref(struct parse_data *pd, YYLTYPE *locp,
48
        const struct cstr *symbol, int offset);
49
static struct const_expr_list *make_expr_list(struct const_expr *expr,
50
        struct const_expr_list *right);
51
static int validate_expr(struct parse_data *pd, struct const_expr *e, int level);
52

53
// XXX decide whether this should be called in functions or in grammar actions
54
static void free_cstr(struct cstr *cs, int recurse);
55
%}
56

57
%define parse.error verbose
58
%define api.pure
59
%locations
60
%define parse.lac full
61
%lex-param { void *yyscanner }
62
/* declare parse_data struct as opaque for bison 2.6 */
63
%code requires {
64
    #define YYSTYPE     TENYR_STYPE
65
    #define YYLTYPE     TENYR_LTYPE
66
    struct parse_data;
67
}
68
%code {
69
    #define yyscanner (pd->scanner)
70
    #define PUSH(State) tenyr_push_state(State, yyscanner)
71
    #define POP         tenyr_pop_state(yyscanner)
72
    #define ERR(...)    tenyr_error(&yylloc, pd, __VA_ARGS__)
73
}
74
%parse-param { struct parse_data *pd }
75
%define api.prefix {tenyr_}
76

77
%start top
78

79
/* precedence rules only matter in constant expressions */
80
%left           '|'
81
%left           '^'
82
%left           '&' "&~"
83
%left           "==" '<' '>' "<=" ">="
84
%left           "<<" ">>" ">>>"
85
%left           '+' '-'
86
%left           '*' '/'
87

88
%token <i>      '[' ']' '.' '(' ')' '+' '-' '*' '~' ',' ';'
89
%token <i>      INTEGER BITSTRING REGISTER
90
%token <cstr>   SYMBOL LOCAL STRSPAN CHARACTER
91
%token          ILLEGAL
92
%token          DBLQUOTE
93

94
/* synonyms for literal string tokens */
95
%token LSH      "<<"
96
%token RSH      ">>>"
97
%token RSHA     ">>"
98
%token EQ       "=="
99
%token GE       ">="
100
%token LE       "<="
101
%token ORN      "|~"
102
%token ANDN     "&~"
103
%token PACK     "^^"
104

105
%token <i> TOL  "<-"
106
%token <i> TOR  "->"
107

108
%token WORD     ".word"
109
%token CHARS    ".chars"
110
%token GLOBAL   ".global"
111
%token SET      ".set"
112
%token ZERO     ".zero"
113

114
%type <ce>      binop_expr expr vexpr atom vatom eref
115
%type <cl>      expr_list
116
%type <cstr>    string stringelt strspan symbol
117
%type <dctv>    directive
118
%type <expr>    rhs rhs_plain lhs lhs_plain
119
%type <i>       arrow regname reloc_op binop unary_op const_unary_op
120
%type <imm>     immediate
121
%type <program> program element data insn
122

123
%union {
124
    int32_t                 i;
125
    struct const_expr      *ce;
126
    struct const_expr_list *cl;
127
    struct expr            *expr;
128
    struct cstr            *cstr;
129
    struct directive       *dctv;
130
    struct element_list    *program;
131
    struct immediate {
132
        int32_t i;
133
        int flags;
134
    } imm;
135
}
136

137
%%
138

139
top
140
    : opt_terminators
141 1
        {   pd->top = NULL; }
142
    | opt_terminators program
143
        {   // Allocate a phantom entry to provide a final context element
144 1
            struct const_expr zs = { .type = CE_IMM, .i = 0 };
145 1
            struct element_list **el = pd->top ? &pd->top->tail->next : &pd->top;
146 1
            *el = make_zeros(pd, &yylloc, &zs); }
147

148
opt_nl
149
    : opt_nl '\n'
150
    | /* empty */
151

152
program
153
    : element terminators
154 1
        {   pd->top = $$ = $1; }
155
    | program element terminators
156 1
        {   struct element_list *p = $1, *d = $element;
157 1
            if (p == NULL) {
158 1
                p = d;
159 1
            } else if (d != NULL) { // an empty string is NULL
160 1
                p->tail->next = d;
161 1
                p->tail = d->tail;
162
            }
163 1
            pd->top = $$ = p;
164
        }
165
    | directive terminators
166 1
        {   pd->top = $$ = NULL;
167 1
            handle_directive(pd, &yylloc, $directive, &pd->top); }
168
    | program directive terminators
169 1
        {   handle_directive(pd, &yylloc, $directive,
170 1
                             pd->top ? &pd->top->tail->next : &pd->top); }
171

172
element
173
    : data
174
    | insn
175
    | symbol ':' opt_nl element[inner]
176 1
        {   add_symbol_to_insn(pd, &yylloc, ($$ = $inner)->elem, $symbol);
177 1
            free_cstr($symbol, 1); }
178

179
opt_terminators : /* empty */ | terminators
180
terminator  : '\n' | ';'
181
terminators : terminators terminator | terminator
182

183
insn
184
    : ILLEGAL
185 1
        {   $$ = calloc(1, sizeof *$$);
186 1
            $$->elem = calloc(1, sizeof *$$->elem);
187 1
            $$->elem->insn.size = 1;
188 1
            $$->elem->insn.u.word = (int32_t)0xffffffff; /* P <- [P + -1] */
189 1
            $$->tail = $$; }
190 1
    | lhs { PUSH(needarrow); } arrow { POP; } rhs
191 1
        {   if ($lhs->deref && $rhs->deref)
192 1
                ERR("Cannot dereference both sides of an arrow");
193 1
            if ($arrow == 1 && !$rhs->deref)
194 1
                ERR("Right arrows must point to dereferenced right-hand sides");
195 1
            $$ = calloc(1, sizeof *$$);
196 1
            $$->elem = make_insn_general(pd, $lhs, $arrow, $rhs);
197 1
            $$->tail = $$; }
198

199
symbol
200
    : SYMBOL
201
    | LOCAL
202

203
string
204
    : stringelt
205
    | string[left] stringelt
206 1
        {   $$ = $left ? $left : $stringelt;
207 1
            if ($left) $$->last->right = $stringelt;
208 1
            if ($stringelt) $$->last = $stringelt; }
209

210
stringelt
211 1
    : DBLQUOTE strspan DBLQUOTE {   $$ = $strspan; }
212 1
    | DBLQUOTE DBLQUOTE         {   $$ = NULL; }
213

214
strspan
215
    : STRSPAN
216
    | strspan[left] STRSPAN
217 1
        {   $$ = $left;
218 1
            $$->last->right = $STRSPAN;
219 1
            $$->last = $$->last->right; }
220

221
data
222 1
    : ".word"  opt_nl expr_list {  POP; $$ = make_data(pd, $expr_list); }
223 1
    | ".zero"  opt_nl expr      {  POP; $$ = make_zeros(pd, &yylloc, $expr); ce_free($expr); }
224 1
    | ".chars" opt_nl string    {  POP; $$ = make_chars($string); free_cstr($string, 1); }
225

226
directive
227
    : ".global" opt_nl SYMBOL
228 1
        {   POP; $directive = make_global(pd, &yylloc, $SYMBOL); free_cstr($SYMBOL, 1); }
229
    | ".set" opt_nl SYMBOL ',' vexpr
230 1
        {   POP; $directive = make_set(pd, &yylloc, $SYMBOL, $vexpr); free_cstr($SYMBOL, 1); }
231

232
expr_list
233
    : vexpr
234 1
        {   $$ = make_expr_list($vexpr, NULL); }
235
    | vexpr ',' opt_nl expr_list[right]
236 1
        {   $$ = make_expr_list($vexpr, $right); }
237

238
lhs
239
    : lhs_plain
240
    | '[' lhs_plain ']'
241 1
        {   $$ = $lhs_plain;
242 1
            $$->deref = 1; }
243

244
lhs_plain
245
    : regname
246 1
        {   $$ = calloc(1, sizeof *$$);
247 1
            $$->x = $regname; }
248

249
rhs
250
    : rhs_plain
251
    | '[' rhs_plain ']'
252 1
        {   $$ = $rhs_plain;
253 1
            $$->deref = 1; }
254

255
rhs_plain
256
    : regname[x] binop regname[y] reloc_op vatom
257 1
        { $$ = make_rhs(0, $x, $binop, $y, $reloc_op, $vatom); }
258
    | regname[x] binop regname[y]
259 1
        {   int adding = $binop == OP_ADD;
260 1
            int type   = adding ? 2 : 0;
261 1
            int op     = adding ? OP_BITWISE_OR : $binop;
262 1
            $$ = make_rhs(type, $x, op, $y, 0, NULL); }
263
    | regname[x]
264 1
        { $$ = make_rhs(1, 0, OP_BITWISE_OR, $x, 0, NULL); }
265
    | regname[x] binop vatom '+' regname[y]
266 1
        { $$ = make_rhs(1, $x, $binop, $y, 1, $vatom); }
267
    | regname[x] binop vatom
268 1
        {   int adding = $binop == OP_ADD || $binop == OP_SUBTRACT;
269 1
            int mult   = $binop == OP_SUBTRACT ? -1 : 1;
270 1
            int type   = adding ? 3 : 1;
271 1
            int op     = mult < 0 ? OP_ADD : $binop;
272 1
            $$ = make_rhs(type, $x, op, 0, mult, $vatom); }
273
    | vatom binop regname[x] '+' regname[y]
274 1
        { $$ = make_rhs(2, $x, $binop, $y, 1, $vatom); }
275
    | vatom binop regname[x]
276 1
        {   int adding = $binop == OP_ADD;
277 1
            int x      = adding ?  0 : $x;
278 1
            int y      = adding ? $x :  0;
279 1
            int op     = adding ? OP_BITWISE_OR : $binop;
280
            // `B <- 0 + C` is type2, `B <- 2 + C` is type1
281 1
            $$ = make_rhs(adding ? 1 : 2, x, op, y, 1, $vatom); }
282
    | vatom
283 1
        { $$ = make_rhs(3, 0, 0, 0, 1, $vatom); }
284
    /* syntax sugars */
285
    | unary_op regname[x] reloc_op vatom
286 1
        { $$ = make_unary($unary_op, $x,  0, $reloc_op, $vatom); }
287
    | unary_op regname[x] '+' regname[y]
288 1
        { $$ = make_unary($unary_op, $x, $y, 0, NULL); }
289
    | unary_op regname[x]
290 1
        { $$ = make_unary($unary_op, $x,  0, 0, NULL); }
291

292
regname
293 1
    : REGISTER { $regname = toupper($REGISTER) - 'A'; }
294

295
immediate
296
    : INTEGER
297 1
        {   $immediate.i = $INTEGER;
298 1
            $immediate.flags = 0; }
299
    | BITSTRING
300 1
        {   $immediate.i = $BITSTRING;
301 1
            $immediate.flags = IMM_IS_BITS; }
302
    | CHARACTER
303 1
        {   $immediate.i = $CHARACTER->tail[-1];
304 1
            $immediate.flags = IMM_IS_BITS;
305 1
            free_cstr($CHARACTER, 1); }
306

307
binop
308
    /* native ops */
309 1
    : '+'   { $$ = OP_ADD              ; }
310 1
    | '-'   { $$ = OP_SUBTRACT         ; }
311 1
    | '*'   { $$ = OP_MULTIPLY         ; }
312 1
    | '<'   { $$ = OP_COMPARE_LT       ; }
313 1
    | "=="  { $$ = OP_COMPARE_EQ       ; }
314 1
    | ">="  { $$ = OP_COMPARE_GE       ; }
315 1
    | '|'   { $$ = OP_BITWISE_OR       ; }
316 1
    | "|~"  { $$ = OP_BITWISE_ORN      ; }
317 1
    | '&'   { $$ = OP_BITWISE_AND      ; }
318 1
    | "&~"  { $$ = OP_BITWISE_ANDN     ; }
319 1
    | '^'   { $$ = OP_BITWISE_XOR      ; }
320 1
    | "<<"  { $$ = OP_SHIFT_LEFT       ; }
321 1
    | ">>"  { $$ = OP_SHIFT_RIGHT_ARITH; }
322 1
    | ">>>" { $$ = OP_SHIFT_RIGHT_LOGIC; }
323 1
    | "^^"  { $$ = OP_PACK             ; }
324 1
    | '@'   { $$ = OP_TEST_BIT         ; }
325
    /* ops implemented by syntax sugar */
326 1
    | '>'   { $$ = -OP_COMPARE_LT      ; }
327 1
    | "<="  { $$ = -OP_COMPARE_GE      ; }
328

329
unary_op
330 1
    : '~'   { $$ = OP_BITWISE_ORN; }
331 1
    | '-'   { $$ = OP_SUBTRACT; }
332

333
arrow
334 1
    : "<-"  { $$ = 0; }
335 1
    | "->"  { $$ = 1; }
336

337
reloc_op
338 1
    : '+'   { $$ = +1; }
339 1
    | '-'   { $$ = -1; }
340

341 1
vexpr : expr        { $$ = $1; validate_expr(pd, $1, 0); }
342 1
vatom : atom        { $$ = $1; validate_expr(pd, $1, 0); }
343

344
expr
345 1
    : atom          { $$ = $1; ce_eval_const(pd, $1, &$1->i); }
346 1
    | binop_expr    { $$ = $1; ce_eval_const(pd, $1, &$1->i); }
347

348
eref
349 1
    : '@'     SYMBOL    { $$ = make_ref (pd, &yylloc, CE_EXT, $SYMBOL);    free_cstr($SYMBOL, 1); }
350
    /* syntax sugars */
351 1
    | '@' '+' SYMBOL    { $$ = make_eref(pd, &yylloc,         $SYMBOL, 1); free_cstr($SYMBOL, 1); }
352

353
binop_expr
354 1
    : expr[x]  '+'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '+', $x, $y, 0); }
355 1
    | expr[x]  '-'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '-', $x, $y, RHS_NEGATE); }
356 1
    | expr[x]  '*'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '*', $x, $y, FORBID_LHS); }
357 1
    | expr[x]  '/'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '/', $x, $y, FORBID_LHS); }
358 1
    | expr[x]  '^'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '^', $x, $y, FORBID_LHS); }
359 1
    | expr[x]  '&'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '&', $x, $y, SPECIAL_LHS); }
360 1
    | expr[x]  '|'  expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  '|', $x, $y, FORBID_LHS); }
361 1
    | expr[x]  "<<" expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  LSH, $x, $y, FORBID_LHS); }
362 1
    | expr[x]  ">>" expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2, RSHA, $x, $y, SPECIAL_LHS); }
363 1
    | expr[x] ">>>" expr[y] { $$ = make_expr(pd, &yylloc, CE_OP2,  RSH, $x, $y, FORBID_LHS); }
364

365
const_unary_op
366 1
    : '~'   { $$ = '~'; }
367 1
    | '-'   { $$ = '-'; }
368

369
atom
370
    : eref
371
    | '(' expr ')'
372 1
        {   $$ = $expr; }
373
    | const_unary_op atom[inner]
374 1
        {   $$ = make_expr(pd, &yylloc, CE_OP1, $const_unary_op, $inner, NULL, 0);
375 1
            ce_eval_const(pd, $$, &$$->i); }
376
    | immediate
377 1
        {   $$ = make_imm(pd, &yylloc, $immediate.i, $immediate.flags); }
378
    | '.'
379 1
        {   $$ = make_expr(pd, &yylloc, CE_ICI, 0, NULL, NULL, IMM_IS_BITS | IS_DEFERRED); }
380
    | LOCAL
381 1
        {   $$ = make_ref(pd, &yylloc, CE_SYM, $LOCAL); free_cstr($LOCAL, 1); }
382

383
%%
384

385 1
int tenyr_error(YYLTYPE *locp, struct parse_data *pd, const char *fmt, ...)
386
{
387
    va_list vl;
388 1
    int col = locp->first_column + 1;
389

390 1
    fflush(stderr);
391
    // We use first_column as a flag to tell us whether pd->lexstate is valid
392
    // enough to provide the diagnostic caret and context.
393 1
    if (locp->first_column >= 0) {
394 1
        fprintf(stderr, "%s\n", pd->lexstate.saveline);
395 1
        fprintf(stderr, "%*s", col, "^");
396 1
        int len = locp->last_column - locp->first_column;
397 1
        while (len-- > 0)
398 1
            fwrite("^", 1, 1, stderr);
399 1
        fwrite("\n", 1, 1, stderr);
400
    }
401

402 1
    va_start(vl, fmt);
403 1
    vfprintf(stderr, fmt, vl);
404 1
    va_end(vl);
405

406 1
    fprintf(stderr, " at line %d", locp->first_line);
407 1
    if (locp->first_column >= 0)
408 1
        fprintf(stderr, " column %d at `%s'", col, tenyr_get_text(pd->scanner));
409 1
    fwrite("\n", 1, 1, stderr);
410

411 1
    pd->errored++;
412 1
    return 0;
413
}
414

415 1
static struct element *make_insn_general(struct parse_data *pd,
416
        struct expr *lhs, int arrow, struct expr *expr)
417
{
418 1
    struct element *elem = calloc(1, sizeof *elem);
419 1
    int dd = ((lhs->deref | (!arrow && expr->deref)) << 1) | expr->deref;
420

421 1
    elem->insn.u.typeany.p  = (unsigned)expr->type;
422 1
    elem->insn.u.typeany.dd = (unsigned)dd;
423 1
    elem->insn.u.typeany.z  = (unsigned)lhs->x;
424 1
    elem->insn.u.typeany.x  = (unsigned)expr->x;
425

426 1
    free(lhs);
427

428 1
    switch (expr->type) {
429 1
        case 0:
430
        case 1:
431
        case 2:
432 1
            elem->insn.u.type012.op  = (unsigned)expr->op;
433 1
            elem->insn.u.type012.y   = (unsigned)expr->y;
434 1
            elem->insn.u.type012.imm = (unsigned)expr->i;
435 1
            break;
436 1
        case 3:
437 1
            elem->insn.u.type3.imm = (unsigned)expr->i;
438
    }
439

440 1
    elem->insn.size = 1;
441

442 1
    if (expr->ce) {
443 1
        int width = (expr->type == 3)
444
            ? MEDIUM_IMMEDIATE_BITWIDTH
445 1
            : SMALL_IMMEDIATE_BITWIDTH;
446 1
        add_deferred_expr(pd, expr->ce, expr->mult, &elem->insn.u.word,
447
                width, 0);
448 1
        expr->ce->insn = elem;
449
    }
450

451 1
    free(expr);
452

453 1
    return elem;
454
}
455

456 1
static struct const_expr *add_deferred_expr(struct parse_data *pd,
457
        struct const_expr *ce, int mult, int32_t *dest, int width, int flags)
458
{
459 1
    struct deferred_expr *n = calloc(1, sizeof *n);
460

461 1
    n->next  = pd->defexprs;
462 1
    n->ce    = ce;
463 1
    n->dest  = dest;
464 1
    n->width = width;
465 1
    n->mult  = mult;
466 1
    n->flags = flags;
467

468 1
    pd->defexprs = n;
469

470 1
    return ce;
471
}
472

473 1
static struct const_expr *make_expr(struct parse_data *pd, YYLTYPE *locp,
474
        enum const_expr_type type, int op, struct const_expr *left,
475
        struct const_expr *right, int flags)
476
{
477 1
    struct const_expr *n = calloc(1, sizeof *n);
478

479 1
    if (left && (left->flags & IS_EXTERNAL) && (flags & FORBID_LHS))
480 0
        tenyr_error(locp, pd, "Expression contains an invalid use of a "
481
                              "deferred expression");
482

483 1
    n->type  = type;
484 1
    n->op    = op;
485 1
    n->left  = left;
486 1
    n->right = right;
487 1
    n->insn  = NULL;    // top expr will have its insn filled in
488 1
    n->flags = ((left  ? left->flags  : 0)  |
489 1
                (right ? right->flags : 0)) | flags;
490 1
    n->srcloc = *locp;
491 1
    n->deferred_name = NULL;
492 1
    n->symbol_name = &n->deferred_name;
493

494 1
    return n;
495
}
496

497 1
static struct const_expr *make_imm(struct parse_data *pd, YYLTYPE *locp,
498
        int val, int flags)
499
{
500 1
    struct const_expr *imm = make_expr(pd, locp, CE_IMM, 0, NULL, NULL, flags);
501 1
    imm->i = val;
502 1
    return imm;
503
}
504

505 1
static struct expr *make_rhs(int type, int x, int op, int y, int mult,
506
        struct const_expr *defexpr)
507
{
508 1
    struct expr *e = calloc(1, sizeof *e);
509

510 1
    e->type  = type;
511 1
    e->deref = 0;
512 1
    e->x     = x;
513 1
    e->op    = op;
514 1
    e->y     = y;
515 1
    e->mult  = mult;
516 1
    e->ce    = defexpr;
517

518 1
    if (op < 0) { // syntax sugar, swapping operands
519
        // `type` must not be e at this point (can't swap operands in type 3)
520 1
        e->op = -op;
521 1
        switch (type) {
522 1
            case 0: e->x = y; e->y = x; break;
523 1
            case 1: e->type = 2; break;
524 1
            case 2: e->type = 1; break;
525
        }
526 1
    }
527

528 1
    if (defexpr) {
529 1
        if (op == OP_PACK)
530 1
            e->ce->flags |= IGNORE_WIDTH;
531 1
        e->i = (int32_t)0xfffffbad; // put in a placeholder that must be overwritten
532
    } else
533 1
        e->i = 0; // there was no expr ; zero defined by language
534

535 1
    return e;
536
}
537

538 1
static struct expr *make_unary(int op, int x, int y, int mult,
539
        struct const_expr *defexpr)
540
{
541
    // tenyr has no true unary ops, but the following sugars are recognised by
542
    // the assembler and converted into their corresponding binary equivalents :
543
    //
544
    // b <- ~b + 2  becomes     b <- a |~ b + 2 (type 0)
545
    // b <- ~b + c  becomes     b <- 0 |~ b + c (type 2)
546
    // b <- -b + 2  becomes     b <- a -  b + 2 (type 0)
547
    // b <- -b + c  becomes     b <- 0 -  b + c (type 2)
548

549 1
    int type = defexpr ? 0 : 2;
550 1
    int xx   = defexpr ? 0 : x;
551 1
    int yy   = defexpr ? x : y;
552 1
    return make_rhs(type, xx, op, yy, mult, defexpr);
553
}
554

555 1
static void free_cstr(struct cstr *cs, int recurse)
556
{
557 1
    if (!cs)
558 1
        return;
559

560 1
    if (recurse)
561 1
        free_cstr(cs->right, recurse);
562

563 1
    free(cs->head);
564 1
    free(cs);
565
}
566

567 1
static struct element_list *make_chars(struct cstr *cs)
568
{
569 1
    struct element_list *result = NULL, **rp = &result;
570

571 1
    struct cstr *p = cs;
572
    struct element_list *t;
573

574 1
    while (p) {
575 1
        char *h = p->head;
576 1
        for (; h < p->tail; h++) {
577 1
            *rp = calloc(1, sizeof **rp);
578 1
            result->tail = t = *rp;
579 1
            rp = &t->next;
580 1
            t->elem = calloc(1, sizeof *t->elem);
581

582 1
            t->elem->insn.u.word = *h;
583 1
            t->elem->insn.size = 1;
584
        }
585

586 1
        p = p->right;
587
    }
588

589 1
    return result;
590
}
591

592 1
static int add_symbol(YYLTYPE *locp, struct parse_data *pd, struct symbol *n)
593
{
594 1
    struct symbol_list *l = calloc(1, sizeof *l);
595

596 1
    l->next = pd->symbols;
597 1
    l->symbol = n;
598 1
    pd->symbols = l;
599

600 1
    return 0;
601
}
602

603 1
static char *coalesce_string(const struct cstr *s)
604
{
605 1
    const struct cstr *p = s;
606 1
    size_t len = 0;
607 1
    while (p) {
608 1
        ptrdiff_t size = p->tail - p->head;
609
        assert(size >= 0);
610 1
        len += (size_t)size;
611 1
        p = p->right;
612
    }
613

614 1
    char *ret = malloc(len + 1);
615 1
    p = s;
616 1
    len = 0;
617 1
    while (p) {
618 1
        ptrdiff_t size = p->tail - p->head;
619
        assert(size >= 0);
620 1
        memcpy(&ret[len], p->head, (size_t)size);
621 1
        len += (size_t)size;
622 1
        p = p->right;
623
    }
624

625 1
    ret[len] = '\0';
626

627 1
    return ret;
628
}
629

630 1
static int add_symbol_to_insn(struct parse_data *pd, YYLTYPE *locp,
631
        struct element *in, struct cstr *symbol)
632
{
633 1
    struct symbol *n = calloc(1, sizeof *n);
634 1
    n->column   = locp->first_column;
635 1
    n->lineno   = locp->first_line;
636 1
    n->resolved = 0;
637 1
    n->next     = in->symbol;
638 1
    n->unique   = 1;
639 1
    n->name     = coalesce_string(symbol);
640 1
    in->symbol = n;
641

642 1
    return add_symbol(locp, pd, n);
643
}
644

645 1
static struct element_list *make_data(struct parse_data *pd,
646
        struct const_expr_list *list)
647
{
648 1
    struct element_list *result = NULL, **rp = &result;
649

650 1
    struct const_expr_list *p = list;
651 1
    while (p) {
652 1
        *rp = calloc(1, sizeof **rp);
653 1
        struct element_list *q = *rp;
654 1
        result->tail = *rp;
655 1
        rp = &q->next;
656

657 1
        struct element *e = q->elem = calloc(1, sizeof *q->elem);
658 1
        e->insn.size = 1;
659 1
        add_deferred_expr(pd, p->ce, 1, &e->insn.u.word, WORD_BITWIDTH, 0);
660 1
        p->ce->insn = e;
661 1
        struct const_expr_list *temp = p;
662 1
        p = p->right;
663 1
        free(temp);
664
    }
665

666 1
    return result;
667
}
668

669 1
static struct element_list *make_zeros(struct parse_data *pd, YYLTYPE *locp,
670
        struct const_expr *size)
671
{
672 1
    if (size->flags & IS_DEFERRED)
673 1
        tenyr_error(locp, pd, "size expression for .zero must not "
674
                              "depend on symbol values");
675

676
    // Continue even in the error case so we return a real data element so
677
    // further errors can be collected and reported. Returning NULL here
678
    // without adding additional complexity to data-users in the grammar would
679
    // cause a segfault.
680

681 1
    struct element_list *result = calloc(1, sizeof *result);
682 1
    result->elem = calloc(1, sizeof *result->elem);
683 1
    result->tail = result;
684 1
    ce_eval_const(pd, size, &result->elem->insn.size);
685 1
    return result;
686
}
687

688 1
static struct directive *make_global(struct parse_data *pd, YYLTYPE *locp,
689
        const struct cstr *symbol)
690
{
691 1
    struct directive *result = calloc(1, sizeof *result);
692 1
    result->type = D_GLOBAL;
693
    // TODO try to eliminate string copy
694 1
    struct global_list *g = result->data = malloc(sizeof *g);
695 1
    ptrdiff_t size = symbol->tail - symbol->head;
696
    assert(size >= 0);
697 1
    g->name = malloc((size_t)size + 1);
698 1
    strcopy(g->name, symbol->head, (size_t)size + 1);
699 1
    return result;
700
}
701

702 1
static struct directive *make_set(struct parse_data *pd, YYLTYPE *locp,
703
        const struct cstr *symbol, struct const_expr *expr)
704
{
705 1
    struct directive *result = calloc(1, sizeof *result);
706 1
    result->type = D_SET;
707

708 1
    struct symbol *n = result->data = calloc(1, sizeof *n);
709 1
    n->column   = locp->first_column;
710 1
    n->lineno   = locp->first_line;
711 1
    n->resolved = 0;
712 1
    n->next     = NULL;
713 1
    n->ce       = expr;
714 1
    n->unique   = 0;
715
    // XXX validate symbol length
716 1
    n->name = coalesce_string(symbol);
717

718 1
    add_symbol(locp, pd, n);
719

720 1
    return result;
721
}
722

723 1
static void handle_directive(struct parse_data *pd, YYLTYPE *locp,
724
        struct directive *d, struct element_list **context)
725
{
726 1
    if (!d)
727 0
        return; // permit NULL directives as no-ops
728

729 1
    switch (d->type) {
730 1
        case D_GLOBAL: {
731 1
            struct global_list *g = d->data;
732 1
            g->next = pd->globals;
733 1
            pd->globals = g;
734 1
            break;
735
        }
736 1
        case D_SET: {
737 1
            struct symbol *sym = d->data;
738 1
            sym->ce->deferred = context;
739 1
            break;
740
        }
741 0
        case D_NULL:
742
        case D_ZERO:
743 0
            tenyr_error(locp, pd, "Unknown directive type %d in %s",
744 0
                        d->type, __func__);
745
    }
746

747 1
    free(d);
748
}
749

750 1
static struct const_expr *make_ref(struct parse_data *pd, YYLTYPE *locp,
751
        enum const_expr_type type, const struct cstr *symbol)
752
{
753 1
    int flags = IMM_IS_BITS | IS_DEFERRED;
754 1
    if (type == CE_EXT)
755 1
        flags |= IS_EXTERNAL;
756 1
    struct const_expr *eref = make_expr(pd, locp, type, 0, NULL, NULL, flags);
757
    struct symbol *s;
758 1
    char *name = coalesce_string(symbol);
759 1
    if ((s = symbol_find(pd->symbols, name))) {
760 1
        eref->symbol = s;
761 1
        eref->symbol_name = &eref->symbol->name;
762 1
        free(name);
763
    } else {
764 1
        eref->deferred_name = name;
765 1
        eref->symbol_name = &eref->deferred_name;
766
    }
767

768 1
    return eref;
769
}
770

771
// make_eref implements syntax sugar :
772
//  `@+var` expands to `@var - (. + 1)`
773 1
static struct const_expr *make_eref(struct parse_data *pd, YYLTYPE *locp,
774
        const struct cstr *symbol, int offset)
775
{
776
    return
777 1
        make_expr(pd, locp, CE_OP2, '-',
778
            make_ref(pd, locp, CE_EXT, symbol),
779
            make_expr(pd, locp, CE_OP2, '+',
780
                make_expr(pd, locp, CE_ICI, 0, NULL, NULL, IMM_IS_BITS | IS_DEFERRED),
781
                make_imm(pd, locp, offset, 0),
782
                0),
783
            0);
784
}
785

786 1
static struct const_expr_list *make_expr_list(struct const_expr *expr,
787
        struct const_expr_list *right)
788
{
789 1
    struct const_expr_list *result = calloc(1, sizeof *result);
790 1
    result->right = right;
791 1
    result->ce = expr;
792 1
    return result;
793
}
794

795 1
static int validate_expr(struct parse_data *pd, struct const_expr *e, int level)
796
{
797 1
    int ok = 1;
798

799 1
    if (!e)
800 1
        return 1;
801

802 1
    struct const_expr *left  = e->left, *right = e->right;
803 1
    int is_binary = left && right;
804

805 1
    ok &= validate_expr(pd, left , level + 1);
806 1
    ok &= validate_expr(pd, right, level + 1);
807

808 1
    if (is_binary) {
809 1
        if ((left->flags  & IS_EXTERNAL) && (right->flags & IS_EXTERNAL)) {
810 1
            ok = 0;
811 1
            tenyr_error(&e->srcloc, pd, "Expression contains more than one "
812
                                        "reference to an external");
813
        }
814
    }
815

816
    // check both left and right to make sure we validate only binary ops
817 1
    if (is_binary && (left->flags & IS_EXTERNAL) && (e->flags & SPECIAL_LHS)) {
818
        // Special rules apply to right-shifts of 12 and masks of 0xfff. This
819
        // is how we express breaking down a large offset into a 20-bit chunk
820
        // and a 12-bit chunk that we reassemble using OP_PACK.
821
        // TODO implement the special relocation types in the linker
822
        // XXX how to characterise the legal possibilities ?
823
        // B <- ((@xx - .) >> 12) ; C <- B ^^ ((@xx - .) & 0xfff)
824
        // B <- ( @xx      >> 12) ; C <- B ^^ ( @xx      & 0xfff)
825 1
        switch (e->op) {
826 1
            case RSHA:  ok &= (level == 0); ok &= e->right->i == 12;    break;
827 1
            case '&':   ok &= (level == 0); ok &= e->right->i == 0xfff; break;
828 0
            case '-':   /* subtraction is always valid */; break;
829 0
            case '+':   /* addition is always valid */; break;
830 0
            default:    ok &= 0; break;
831
        }
832

833 1
        if (!ok) {
834
            // At this point e->srcloc may not correspond to lexstate. Until we
835
            // get around to making a "where this was" object, we inhibit
836
            // printing the handy caret, by invalidating the column
837
            // information.
838 1
            e->srcloc.first_column = -1;
839 1
            tenyr_error(&e->srcloc, pd,
840
                        "Expression contains an invalid use of a "
841
                        "deferred binary expression");
842
        }
843
    }
844

845 1
    return ok;
846
}
847

Read our documentation on viewing source code .

Loading